I was reading the specification about HTTP/1.1 redirection codes. I have many questions:
There's a text like this:
If the 301/302/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.
Q: In what sense is this applied by browsers? I never saw any 301/302 response making my browser ask me if I wanted to confirm the operation (example: receiving a form by PHP and then redirecting to a new output).
It's clear to me that most of the times we Process-and-Redirect using a 302, instead of 303 (See other - which was created for exactly THAT purpose). However, I'm confused about 301 302 (please note: the intended, original behavior) and 307. Q: What are the differences between them in a practical example / use case?
Most 301/302 redirect responses occur on regular GET requests (as opposed to POST requests) so there is no confirmation needed. Also, even though confirmation for non GET/HEAD requests is technically recommended by the RFC, the RFC also mentions that:
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.
302 tells the user agent to continue using the old uri in future requests. 303 tells the user agent to use the new uri in future requests.
In addition, as the note in the RFC you link to mentions:
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.
I'd argue that the RFC should be changed so that If the 301/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.
Should be rewritten as If the 301/302 status code is received in response to a request other than GET or HEAD, the user agent SHOULD 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.
Since otherwise most current user agent are violating the RFC.
Related
My website has a 1% random chance of redirecting visitors to this YouTube video.
The server currently sends the good-old 302, but I want it to have better semantics.
I don't know if the redirect is permanent or temporary. It's permanent in the sense that people always have a 1% chance of being redirected, and it's temporary in the sense that people don't get redirected every single time.
None of the current 3xx response status codes match my website's behavior.
HTTP 3xx redirects (source: Wikipedia)
301 Moved Permanently
This and all future requests should be directed to the given URI.[21]
"This and all future requests" - nope, not all future requests.
302 Found (Previously "Moved temporarily")
Tells the client to look at (browse to) another url. 302 has been superseded by 303 and 307. This is an example of industry practice contradicting the standard. The HTTP/1.0 specification (RFC 1945) required the client to perform a temporary redirect (the original describing phrase was "Moved Temporarily"),[22] but popular browsers implemented 302 with the functionality of a 303 See Other. Therefore, HTTP/1.1 added status codes 303 and 307 to distinguish between the two behaviours.[23] However, some Web applications and frameworks use the 302 status code as if it were the 303.[24]
This is confusing. It does state, "302 has been superseded by 303 and 307," so I guess this is obsolete yet still commonly used?
303 See Other (since HTTP/1.1)
The response to the request can be found under another URI using the GET method. When received in response to a POST (or PUT/DELETE), the client should presume that the server has received the data and should issue a new GET request to the given URI.[25]
"The response to the request can be found under another URI" - Rickroll is not the response to the original request. It has nothing to do with my site! "When received in response to a POST (or PUT/DELETE), the client should presume that the server has received the data and should issue a new GET request to the given URI." The last sentence of the 303 description doesn't work with my redirect.
307 Temporary Redirect (since HTTP/1.1)
In this case, the request should be repeated with another URI; however, future requests should still use the original URI. In contrast to how 302 was historically implemented, the request method is not allowed to be changed when reissuing the original request. For example, a POST request should be repeated using another POST request.[30]
"In this case, the request should be repeated with another URI; however, future requests should still use the original URI." Yes! This is what my redirect is. "...the request method is not allowed to be changed when reissuing the original request. For example, a POST request should be repeated using another POST request." Unfortunately, this doesn't work with my redirect. My site randomly Rickrolls users even when they submit forms (POST method).
308 Permanent Redirect (RFC 7538)
The request and all future requests should be repeated using another URI. 307 and 308 parallel the behaviors of 302 and 301, but do not allow the HTTP method to change. So, for example, submitting a form to a permanently redirected resource may continue smoothly.[31]
308 has the same issue as 301 because not all future requests should go to the Rickroll video. Furthermore, the method isn't allowed to change.
What HTTP response status code should my server send for random-chance redirects that have nothing to do with my actual site?
The official source for HTTP response status codes is RFC7231, not Wikipedia.
You should peruse RFC7231 Section 6.4 for the explanation of 3XX status codes.
The "redirecting visitors by random chance" thing is irrelevant to the actual redirection,
therefore the status code that fits your requirement is 303,
which is explained in Section 6.4.4 as follows (emphasis mine):
The 303 (See Other) status code indicates that the server is
redirecting the user agent to a different resource, as indicated by a
URI in the Location header field, which is intended to provide an
indirect response to the original request. A user agent can perform
a retrieval request targeting that URI (a GET or HEAD request if
using HTTP), which might also be redirected, and present the eventual
result as an answer to the original request. Note that the new URI
in the Location header field is not considered equivalent to the
effective request URI.
303 fits your requirement for three reasons:
"to a different resource": the resource your visitors are redirected to is not the same resource they originally requested.
"perform a retrieval request": the eventual resource is acquired using a GET or HEAD request.
"not considered equivalent": the original request URI must not be replaced by the new URI because it is not equivalent, in other words, it is temporary.
Why not 302?
Because of this part of the explanation in Section 6.4.3 (emphasis mine):
For historical reasons, a user agent MAY change the request
method from POST to GET for the subsequent request.
In other words, the user agent can use either the same request method or a different request method.
The flexibility that the specification allows for 302 doesn't fit your requirement.
What is the correct behavior expected of a POST => 302 redirect to GET?
In chrome (and likely most every browser), after I POST (to a resource that wants me to redirect) and I receive a 302 redirect, the browser automatically issues a GET on the 302 location. This is even a well known pattern. But the way I read the spec, it seems to suggest this should not happen.
The HTTP spec says
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.
And fiddler is showing:
REQUEST 1: POST URLA
RESPONSE 1: 302 redirect to URLB
REQUEST 2: GET URLB
The section above seems to say that the browser should not make the GET request? What am I missing?
Something earlier in the spec that makes this section irrelevant
My understanding of automatically redirect is wrong (and the chrome browser that did the GET wasn't really automatically redirecting)
My understanding of confirmed this as a user
Something else?
The very next line in the spec begins:
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.
And immediately after that, it explains how a 303 should be handled, and it's exactly what you're seeing.
If you're asking why servers are still using 302 instead of 307, which all current browsers will handle correctly, it's because old browsers won't handle it. If you're wondering why browsers handle 302 as 303, it's because old servers expect it. There's really no way out of that loop, and it would probably be better for HTTP to just revert 302 to mean what it used to mean, and deprecate it (for non-GET/HEAD) in favor of 307.
abarnert was right ! I had the same issue with Google App Engine but I found a different solution.
My issue with appengine was,I did a POST with a form to a GO formHandler at backend. But it was executed as follow.
request 1: GET /formHandler -> response 1: 302 Found
request 1: POST /formHandler -> response 1: 302 Found
request 1: GET /formHandler -> response 1: 200 Ok.
Additionaly I got
No 'Access-Control-Allow-Origin' header is present on the requested resource
Which was a CORS problem.
However the solutions turns out to be to use HTTPS instead of HTTP.
Then you will have
request : POST /formHandler -> response : 200 Ok
You may want to read http://greenbytes.de/tech/webdav/draft-ietf-httpbis-p2-semantics-22.html#rfc.section.6.4.p.3, which tries to clarify the situation.
Note: In HTTP/1.0, the status codes 301 (Moved Permanently) and 302 (Found) were defined for the first type of redirect ([RFC1945], Section 9.3). Early user agents split on whether the method applied to the redirect target would be the same as the original request or would be rewritten as GET. Although HTTP originally defined the former semantics for 301 and 302 (to match its original implementation at CERN), and defined 303 (See Other) to match the latter semantics, prevailing practice gradually converged on the latter semantics for 301 and 302 as well. The first revision of HTTP/1.1 added 307 (Temporary Redirect) to indicate the former semantics without being impacted by divergent practice. Over 10 years later, most user agents still do method rewriting for 301 and 302; therefore, this specification makes that behavior conformant when the original request is POST.
RESTful Web Services encourages the use of HTTP 303 to redirect clients to the canonical representation of a resource. It only discusses topic in the context of HTTP GET.
Does this apply to other HTTP methods as well? If a client attempts a HTTP PUT or DELETE to a non-canonical URI, is it acceptable (and/or recommended) to return HTTP 303? What is the best practice and why?
This status code is generally applicable to any HTTP method. It is primarily used to allow the output of a POST action to redirect the user agent to a selected resource, since doing so provides the information corresponding to the POST response in a form that can be separately identified, bookmarked, and cached independent of the original request.
Source: https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-p2-semantics-21#section-7.4.4
I just discovered an interesting section in the book. According to page 378 section 302 ("Found"):
This status code is the ultimate source of most redirection-related confusion. It’s supposed to be handled just like 307 (“Temporary Redirect”). In fact, in HTTP 1.0 its name
was “Moved Temporarily.” Unfortunately, in real life most clients handle 302 just like
303 (“See Other”). The difference hinges on what the client is supposed to do when it
gets a 302 in response to a PUT, POST, or DELETE request. See the entry for 307 below
if you’re interested in the details.
To resolve this ambiguity, in HTTP 1.1 this response code was renamed to “Found,”
and response code 307 was created.
In other words, HTTP 302 was split into HTTP 303 and 307.
Next, on page 380 section 307 ("Temporary Redirect"):
For GET requests, where the only thing being requested is that the server send a representation, this status code is identical to 303 (“See Other”). A typical case where 307
is a good response to a GET is when the server wants to send a client to a mirror site.
But for POST, PUT, and DELETE requests, where the server is expected to take some
action in response to the request, this status code is significantly different from 303.
A 303 in response to a POST, PUT, or DELETE means that the operation has succeeded
but that the response entity-body is not being sent along with this request. If the client
wants the response entity-body, it needs to make a GET request to another URI.
A 307 in response to a POST, PUT, or DELETE means that the server has not even tried
to perform the operation. The client needs to resubmit the entire request to the URI in
the Location header.
In other words, HTTP POST, PUT, DELETE are legal on HTTP 303, 307. The above paragraph explains the expected behavior.
That being said, I'm quoting the book here, not the HTTP specification (which is suspiciously silent on the expected behavior).
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.
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.