Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

http.Redirect() with headers

Tags:

http

go

I have a web page that emulates authorizing API access. The user enters an API url and an authorization key (let's say "true" or "false"). On the Go side, there's a handler function for this path which reads the form and generates a token based on the authorization key.
Ideally, I'd like to save the token as a header and redirect the request to the proper handler based on the API url entered. However, when I use http.Redirect(), my header does not get sent as part of the request.

func createTokenHandler(w http.ResponseWriter, r *http.Request) {
    r.ParseForm()
    path := r.FormValue("path")
    auth := r.FormValue("auth") // let's say "true" or "false"
    w.Header().Set("auth", auth)
    http.Redirect(w, r, path, http.StatusFound) // is this the correct http code?
}

// path redirects to this handler
func otherPathHandler(w http.ResponseWriter, r *http.Request) {
    // these were necessary for cross-domain requests to work with custom header, keeping them
    w.Header().Set("Access-Control-Allow-Origin", "*")
    w.Header().Set("Access-Control-Allow-Headers", "auth")
    auth = r.Header.Get("auth")
    if auth == "true" {
        w.Write([]byte("Validated, here's the API response."))
        // continue
    }
}

There may be several API urls with different paths, but my thought process has the token being written as a header in that same handler function every time. I'm designing it this way because the API url may eventually redirect to different domains, so I'd like to keep it separate from reading the form.
Google tells me to use Client.CheckRedirect somehow, but I'm not sure how to implement it in my handler functions. How can I redirect while keeping my headers? Thank you!

like image 388
Peemster Avatar asked Mar 31 '16 23:03

Peemster


People also ask

Can you redirect with headers?

Redirection in PHP can be done using the header() function. To setup, a simple redirect simply creates an index.

How do I redirect using HTTP?

In HTTP, redirection is triggered by a server sending a special redirect response to a request. Redirect responses have status codes that start with 3 , and a Location header holding the URL to redirect to. When browsers receive a redirect, they immediately load the new URL provided in the Location header.

Is 302 a redirect?

A 302 redirect is a temporary redirect. The purpose of a 302 redirect is to propagate changes to a forwarding address quickly, so traffic is moved to your new location rapidly. If you're not sure what kind of redirect to use, we suggest using a 302 redirect.


1 Answers

It's because the HTTP standard does not pass through HTTP headers on an 302/301 directive. It's not a GoLang issue, it's an HTTP 1.0 (and 2.0?) standards issue.

You are thinking correctly, using the POST-REDIRECT-GET pattern for common FORM postings to your web app (it prevents the old browser-refresh "Do you want to resubmit the form?" annoying error).

And btw, yes that's the correct status code. Note that http.StatusFound is a 302 code, which indicates it is a temp move. Never use the 301 Permanent Move status for a Postback redirect.

There are some common work-arounds though.

Sessions

Several server-side languages have Sessions that store the value on the backend.

  • store the value/result in a variable tied to the user's session on the backend DB
  • redirect
  • read the session value on the new page load

ASP.NET is one such backend language. ASP.NET sessions ties a session to a user by 1) creating a session upon the first hit to the server and 2) taking the session_id and setting a brower-session (only valid while the browser session is active, close the browser and the cookie is removed). That way on every "request" to the server, the cookie is read for the sessions_id, it is grabbed from your data store, and populates the Session user var.

Personally, I've never duplicated this functionality in Go. But, one could.

Note, this really the only way to complete secure your "secret" token, if it is a secret. Then again, one could steal the session_id and impersonate the request. Then again, one could implement a 4-way browser fingerprint to help limit impersonation. Then again, if one is able to sniff the cookie that has the session_id, then they would be able to sniff all the parameters of the fingerprint method (except IP!).

Temp Cookie

My personal favorite is storing the value in a tmp browser-session cookie with an expiration of Now() -1 (meaning, it will expire immediately). This allows you to read the cookie only 1 time, on the redirect's web request, before the browser expires it after that request.

It's a trick I picked up from ASP.NET MVC, and I enforced on all of my controllers (by disabling Sessions and writing my own temp cookie handler).

Just note that it will not be private/secret: it will sent over your connection. Even if HTTPS, it will still be seen in the browser's add-ons, cookie handlers, etc. Yes, you could "encrypt" the value,a nd decrypt it back on the server side for security: but then, it's only as strong as your encryption (and bloats your request/response sizes).

Good 'ol Querystring Parameter

Can't beat:

/my/url?token=23462345345345

Since you were trying to put it into the header, it isn't a secret anyways.

like image 58
eduncan911 Avatar answered Sep 19 '22 15:09

eduncan911