What type of redirect should I be using to redirect a user to a connection page if he needs to be authenticated before using one service of my website ?
Just to be sure using the right numbers for the crawler's to witness what a good student I am !
Available redirection statuses:
301 Moved Permanently
The 301 (Moved Permanently) status code indicates that the target
resource has been assigned a new permanent URI.
302 Found
The 302 (Found) status code indicates that the target resource resides
temporarily under a different URI.
303 See Other
The 303 (See Other) status code indicates that the server is
redirecting the user agent to a different resource.
304 Not Modified
There is no need for the server to transfer a representation of the
target resource because the request indicates that the client already
has a valid representation.
307 Temporary Redirect
This status code is similar to 302 (Found), except that it does not
allow changing the request method from POST to GET.
308 Permanent Redirect
This status code is similar to 301 (Moved Permanently), except that it
does not allow changing the request method from POST to GET.
Statuses 305 Use Proxy and 306 (Unused) are respectively deprecated and no longer used.
So by default, I would choose the 303 See Other, since it's the one that suits your needs the best.
You should not redirect a user if he need to be logged in to view an URL.
This URL should shoot a 401 status with a form to let your user log in directly. And then return him the content with an HTTP 200 on the same URL.
Some information on 401 from HTTP specifications:
401 Unauthorized
The request requires user authentication. The
response MUST include a WWW-Authenticate header field (section 14.47)
containing a challenge applicable to the requested resource. The
client MAY repeat the request with a suitable Authorization header
field (section 14.8). If the request already included Authorization
credentials, then the 401 response indicates that authorization has
been refused for those credentials. If the 401 response contains the
same challenge as the prior response, and the user agent has already
attempted authentication at least once, then the user SHOULD be
presented the entity that was given in the response, since that entity
might include relevant diagnostic information. HTTP access
authentication is explained in "HTTP Authentication: Basic and Digest
Access Authentication" [43].
I'm building a test tool with Go. This tool can retrieve a specific URL by doing a POST request to an endpoint which returns a 303 with the Location to test. Sometimes this location itself is redirected with a 301 which I want to follow as well.
Test tool -> POST /get-url-to-test -> 303 Location: /other -> GET /other -> 301 Location: /new-other (stops here because initial request is POST)
As we can see in Go's source (lines 241 to 257), it seems like GET requests follow 301 redirects, but not POST requests:
http://golang.org/src/net/http/client.go
Why is that? Is that part of an HTTP spec? Is this an decision that was made by the Go community?
The reason I'm asking is because in my case, I'd have to manually do a new GET request to get to the URL redirected to by /other, I think.
EDIT 1: I made a mistake before: the /other resource is being fetched by Go with a GET request. But since it returns a 301 and the initial request was a POST, Go stops redirecting on the 301. That seems odd. Am I missing something?
EDIT 2: This may be a bug, I've opened an issue on Github: https://github.com/golang/go/issues/9348
The HTTP RFC 2616 says:
10.3 Redirection 3xx
This class of status code indicates that further action needs to be taken by the user agent in order to fulfill the request. The action required MAY be carried out by the user agent
without interaction with the user if and only if the method used in
the second request is GET or HEAD.
I have a webpage that when landed on, will detect a user's physical location and then redirect them to the page most appropriate for the user.
What HTTP Status Code should be used for this redirect?
If there is a URI for the requester to utilize that would allow them to end up the same place without a redirect, then a 303 makes sense (as sjstrutt answered) as they should use the new location's URI. If not, a 302 makes sense to me because they should continue to use the Request-URI for future requests as you will then be redirecting them to a location lacking a URI they could otherwise request.
Heres what w3.org says about 302 status codes:
10.3.3 302 Found
The requested resource resides temporarily under a different URI.
Since the redirection might be altered on occasion, the client SHOULD
continue to use the Request-URI for future requests. This response is
only cacheable if indicated by a Cache-Control or Expires header
field.
The temporary URI SHOULD be given by the Location field in the
response. Unless the request method was HEAD, the entity of the
response SHOULD contain a short hypertext note with a hyperlink to the
new URI(s).
If the 302 status code is received in response to a request other than
GET or HEAD, the user agent MUST NOT automatically redirect the
request unless it can be confirmed by the user, since this might
change the conditions under which the request was issued.
...
Emphasis mine.
As an aside: CodeIgniter's redirect() function defaults to 302, but mentions a 301 might be used for search engine redirects. Obviously that was their decision, but I figured I would throw that into the mix as it is a widely used web framework and I assume they have put some thought into it.
The appropriate response status code for a successful content negotiation is either 301, 302, or 307, depending on whether the redirect is permanent or only temporary.
But in any case, server-driven negotiation should always state which information the decision was based on. In HTTP, it’s the Vary response header field that specifies a list of request header fields that were used in this process.
Unfortunately, the client’s IP address (I guess you’re translating those into geolocation information) is not an option here. So a permanent redirect is not an option either, unless you indicate the response not to be cached, otherwise it could be cached by clients or intermediary proxies. So I would either use 302 or 307.
I believe that HTTP 303 is probably the most appropriate status code for a situation like this, though it may not be compatible with pre-HTTP 1.1 clients.
The HTTP 303 Status Code states (Note: I have bolded the parts that I feel are most important):
The response to the request can be found under a different URI and SHOULD be retrieved using a GET method on that resource. This method exists primarily to allow the output of a POST-activated script to redirect the user agent to a selected resource. The new URI is not a substitute reference for the originally requested resource. The 303 response MUST NOT be cached, but the response to the second (redirected) request might be cacheable.
I am building an API for a web service and I have been asking myself. Imagine there as an API call to create a new project, like /api/project/create.json and it redirects (with a 302 Redirect) to the newly created project, say /api/project/123.json. If the first request is sent via POST, where is specifed, that the second URI must be retrived with GET?
Is there any RFC that states, that redirects always must be followed with GET? Or is it valid client behavior to just change the URL and send the same POST request again to the new URL?
Imagine I have and old API server and a new API server and I wanted to redirect the clients POST-Request to the new API-URL. What do I have to do?
If the first request is sent via POST, where is specifed, that the second URI must be retrived with GET?
Nowhere.
Is there any RFC that states, that redirects always must be followed with GET? Or is it valid client behavior to just change the URL and send the same POST request again to the new URL?
No, actually the RFC (RFC 2616) states that changing the method name on 301 and 302 is incorrect.
See also http://greenbytes.de/tech/webdav/draft-ietf-httpbis-p2-semantics-19.html#status.3xx for more information.
Imagine I have and old API server and a new API server and I wanted to redirect the clients POST-Request to the new API-URL. What do I have to do?
I would recommend using status code 307 (because there are fewer browser bugs around that one).
When a user is not logged in and tries to access a page that requires login, what is the correct HTTP status code for a redirect to the login page?
I am asking because none of the 3xx response codes set out by the W3C seem to fit the requirements:
10.3.1 300 Multiple Choices
The requested resource corresponds to
any one of a set of representations,
each with its own specific location,
and agent- driven negotiation
information (section 12) is being
provided so that the user (or user
agent) can select a preferred
representation and redirect its
request to that location.
Unless it was a HEAD request, the
response SHOULD include an entity
containing a list of resource
characteristics and location(s) from
which the user or user agent can
choose the one most appropriate. The
entity format is specified by the
media type given in the Content- Type
header field. Depending upon the
format and the capabilities of
the user agent, selection of the most
appropriate choice MAY be performed
automatically. However, this
specification does not define any
standard for such automatic selection.
If the server has a preferred choice
of representation, it SHOULD include
the specific URI for that
representation in the Location field;
user agents MAY use the Location field
value for automatic redirection. This
response is cacheable unless indicated
otherwise.
10.3.2 301 Moved Permanently
The requested resource has been
assigned a new permanent URI and any
future references to this resource
SHOULD use one of the returned URIs.
Clients with link editing capabilities
ought to automatically re-link
references to the Request-URI to one
or more of the new references returned
by the server, where possible. This
response is cacheable unless indicated
otherwise.
The new permanent URI SHOULD be given
by the Location field in the response.
Unless the request method was HEAD,
the entity of the response SHOULD
contain a short hypertext note with a
hyperlink to the new URI(s).
If the 301 status code is received in
response to a request other than GET
or HEAD, the user agent MUST NOT
automatically redirect the request
unless it can be confirmed by the
user, since this might change the
conditions under which the request was
issued.
Note: When automatically redirecting a POST request after
receiving a 301 status code, some existing HTTP/1.0 user agents
will erroneously change it into a GET request.
10.3.3 302 Found
The requested resource resides
temporarily under a different URI.
Since the redirection might be altered
on occasion, the client SHOULD
continue to use the Request-URI for
future requests. This response is only
cacheable if indicated by a
Cache-Control or Expires header field.
The temporary URI SHOULD be given by
the Location field in the response.
Unless the request method was HEAD,
the entity of the response SHOULD
contain a short hypertext note with a
hyperlink to the new URI(s).
If the 302 status code is received in
response to a request other than GET
or HEAD, the user agent MUST NOT
automatically redirect the request
unless it can be confirmed by the
user, since this might change the
conditions under which the request was
issued.
Note: RFC 1945 and RFC 2068 specify that the client is not allowed
to change the method on the redirected request. However, most
existing user agent implementations treat 302 as if it
were a 303
response, performing a GET on the Location field-value regardless
of the original request method. The status codes 303 and 307 have
been added for servers that wish to make unambiguously clear which
kind of reaction is expected of the client.
10.3.4 303 See Other
The response to the request can be
found under a different URI and SHOULD
be retrieved using a GET method on
that resource. This method exists
primarily to allow the output of a
POST-activated script to redirect the
user agent to a selected resource. The
new URI is not a substitute reference
for the originally requested resource.
The 303 response MUST NOT be cached,
but the response to the second
(redirected) request might be
cacheable.
The different URI SHOULD be given by
the Location field in the response.
Unless the request method was HEAD,
the entity of the response SHOULD
contain a short hypertext note with a
hyperlink to the new URI(s).
Note: Many pre-HTTP/1.1 user agents do not understand the 303
status. When interoperability with such clients is a concern, the
302 status code may be used instead, since most user agents react
to a 302 response as described here for 303.
10.3.5 304 Not Modified
If the client has performed a
conditional GET request and access is
allowed, but the document has not been
modified, the server SHOULD respond
with this status code. The 304
response MUST NOT contain a
message-body, and thus is always
terminated by the first empty line
after the header fields.
The response MUST include the
following header fields:
- Date, unless its omission is required by section 14.18.1 If a
clockless origin server obeys these
rules, and proxies and clients add
their own Date to any response
received without one (as already
specified by [RFC 2068], section
14.19), caches will operate correctly.
- ETag and/or Content-Location, if the header would have been sent
in a 200 response to the same request
- Expires, Cache-Control, and/or Vary, if the field-value might
differ from that sent in any previous response for the same
variant If the conditional GET used a strong cache validator (see
section 13.3.3), the response SHOULD
NOT include other entity-headers.
Otherwise (i.e., the conditional GET
used a weak validator), the response
MUST NOT include other entity-headers;
this prevents inconsistencies between
cached entity-bodies and updated
headers.
If a 304 response indicates an entity
not currently cached, then the cache
MUST disregard the response and repeat
the request without the conditional.
If a cache uses a received 304
response to update a cache entry, the
cache MUST update the entry to reflect
any new field values given in the
response.
10.3.6 305 Use Proxy
The requested resource MUST be
accessed through the proxy given by
the Location field. The Location field
gives the URI of the proxy. The
recipient is expected to repeat this
single request via the proxy. 305
responses MUST only be generated by
origin servers.
Note: RFC 2068 was not clear that 305 was intended to redirect a
single request, and to be generated by origin servers only. Not
observing these limitations has significant security consequences.
10.3.7 306 (Unused)
The 306 status code was used in a
previous version of the specification,
is no longer used, and the code is
reserved.
10.3.8 307 Temporary Redirect
The requested resource resides
temporarily under a different URI.
Since the redirection MAY be altered
on occasion, the client SHOULD
continue to use the Request-URI for
future requests. This response is only
cacheable if indicated by a
Cache-Control or Expires header field.
The temporary URI SHOULD be given by
the Location field in the response.
Unless the request method was HEAD,
the entity of the response SHOULD
contain a short hypertext note with a
hyperlink to the new URI(s) , since
many pre-HTTP/1.1 user agents do not
understand the 307 status. Therefore,
the note SHOULD contain the
information necessary for a user to
repeat the original request on the new
URI.
If the 307 status code is received in
response to a request other than GET
or HEAD, the user agent MUST NOT
automatically redirect the request
unless it can be confirmed by the
user, since this might change the
conditions under which the request was
issued.
I'm using 302 for now, until I find the correct answer.
Update & conclusion:
HTTP 302 is better since its known to have best compatibility with clients/browsers.
I'd say 303 see other 302 Found:
The requested resource resides temporarily under a different URI. Since the redirection might be altered on occasion, the client SHOULD continue to use the Request-URI for future requests. This response is only cacheable if indicated by a Cache-Control or Expires header field.
fits a login page most closely in my opinion. I initially considered 303 see other which would work just as well. After some thought, I'd say 302 Found is more fitting because the requested resource was found, there just is another page to go through before it can be accessed. The response doesn't get cached by default which is fine as well.
This is a misuse of HTTP redirection mechanism. If user is not authorized then your app must return 401 Unauthorized. In case that the user is authorized but does not have an access to the requested resource then 403 Forbidden must be returned.
You should do the redirect on client side, e.g. by javascript. status code for redirection because required authorization does not exist. Using 30x for this does not conform to HTTP.
How to Think About HTTP Status Codes by Mark Nottingham
401 Unauthorized triggers HTTP’s request authentication mechanism.
401 Unauthorized status code requires presence of WWW-Authenticate header that supports various authentication types:
WWW-Authenticate: <type> realm=<realm>
Bearer, OAuth, Basic, Digest, Cookie, etc
Hypertext Transfer Protocol (HTTP) Authentication Scheme
Registry
Cookie-based HTTP Authentication - DRAFT
I think the appropriate solution is the HTTP 401 (Not Authorized) header.
http://en.wikipedia.org/wiki/HTTP_codes#4xx_Client_Error
The purpose of this header is exactly this. But, instead of redirecting to a login page, the correct process would be something like:
User not logged try to access a login-restricted page.
system identifies user is not logged
system returns HTTP 401 header, AND display the login form in the same response (not a redirect).
This is a good practice, like providing a useful 404 page, with sitemap links, and a search form for example.
See you.
Lots of compelling and contradictory responses here! How to choose?
Finalists:
302 Found
Indicates that the resource requested has been
temporarily moved to the URL given by the Location header. A browser
redirects to this page but search engines don't update their links to
the resource.
The specification requires the method (and the body) not be
altered when the redirection is performed, but not all user-agents
conform. It
is therefore recommended to set the 302 code only as a response for
GET or HEAD methods and to use 307 Temporary Redirect instead, as the
method change is explicitly prohibited in that case.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/302
Vague, possibly buggy, and maybe outdated, but could work, especially for GET requests.
307 Temporary Redirect
The resource requested has been temporarily moved to the URL given by
the Location header.
The only difference between 307 and 302 is that 307 guarantees that
the method and the body will not be changed when the redirected
request is made. With 302, some old clients were incorrectly changing
the method to GET: the behavior with non-GET methods and 302 is then
unpredictable on the Web, whereas the behavior with 307 is
predictable. For GET requests, their behavior is identical.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/307
My original take was that if your application supports HTTP 1.1+, this would be the newer, clearer way to make a temporary redirect.
401 Unauthorized
indicates that the client request has not been completed because it
lacks valid authentication credentials for the requested resource.
This status code is sent with an HTTP WWW-Authenticate response header
that contains information on how the client can request for the
resource again after prompting the user for authentication
credentials.
This status code is similar to the 403 Forbidden status code, except
that in situations resulting in this status code, user authentication
can allow access to the resource.
I agree this was probably intended to be the correct response code to say, "Not until you sign in." But almost every webapp uses HTML forms with Cookies to sign-in and this HTTP code doesn't allow "Cookie" as an authentication scheme:
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/WWW-Authenticate
and
https://www.iana.org/assignments/http-authschemes/http-authschemes.xhtml
A few people have pointed out that someone drafted a "Cookie" scheme in 2009: WWW-Authenticate Cookie
https://datatracker.ietf.org/doc/html/draft-broyer-http-cookie-auth-00
Not sure why that didn't fly. Maybe because that's outside the realm of HTTP?
Without "Cookie" as an option, I think this is not suitable for HTML-and-Cookie based authentication.
Survey
In the absence of an undeniable single "correct" answer, I looked at what a few industry leaders were doing.
Google: 302 Redirect to Sign In Page
Request URL: https://mail.google.com/mail/u/0/?tab=cm Request Method:
GET Status Code: 302
Response:
content-type: text/html; charset=UTF-8 location:
https://accounts.google.com/ServiceLogin?service=mail&passive=1209600&osid=1&continue=https://mail.google.com/mail/u/0/?tab%3Dcm&followup=https://mail.google.com/mail/u/0/?tab%3Dcm&emr=1
Microsoft: 302 Redirect to Sign In page
Request URL:
https://outlook.live.com/mail/0/?authRedirect=true&state=0 Request
Method: GET Status Code: 302
Response: Location:
https://outlook.live.com/owa/0/?state=1&redirectTo=aHR0cHM6Ly9vdXRsb29rLmxpdmUuY29tL21haWwvMC8
Facebook: 302 Redirect to Sign In Page
Request URL: https://www.facebook.com/friends Request Method: GET
Status Code: 302
Response: location:
https://www.facebook.com/login.php?next=https%3A%2F%2Fwww.facebook.com%2Ffriends
Twitter: 200 with interstitial sign-in page
Request URL: https://twitter.com/messages/ Request Method: GET Status
Code: 200 (from service worker)
Me: 307: Temporary Redirect
I've used this for over a decade and never had a problem. Not suggesting that others adopt it, just saying it works as advertised as a 302 alternative in every major browser. I could be convinced to switch to using 302 as a result of researching this answer.
Conclusion
302 is the de-facto standard for redirects, unless you require a POST to be redirected to another POST, which I didn't try.
Really, I think a POST should either succeed or fail outright. POST causes a state change on the server (such as adding a product to inventory) and you really want to know if the change was processed and how many times. Redirecting would raise the question of whether your change was accepted or not before the redirect. Once you decide to NEVER redirect a POST, then 302 and 307 are equivalent. The "bugs" in 302 were in unrealistic use cases. Therefore, 307 should never have been created. Also 302 is more popular, so likely to be best supported.
The nice thing about using a single code for all temporary redirects is that you don't have to worry about the reason for the redirect.
200 with JavaScript throwing up an interstitial sign-in page is another option, probably more suited to single-page webapps. You asked for the page, you got the page, but you're going to be forced to sign in before you can see the contents.