Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Logins and Redirects: What is the best HTTP flow for a webapp login?

This question is a question about login flows for web-apps in general. I'm most interested in answers that optimize for usability and performance while maintaining security.

What is the most appropriate way to handle unauthenticated requests to bookmarked URLs?

To demonstrate the problem, here are some routes and respective behaviors for an example application:

GET /login         -> Display the authentication form
POST /processLogin -> process the username and password, 
                            if unauthentic...re-render the login form; 
                            otherwise...display the default page
GET /secret         -> if authenticated...display the secret resource;
                       otherwise...display a login form
POST /secret        -> if authenticated...perform a desirable, but potentially 
                                          non-idempotent action on the secret 
                                          resource
                       otherwise...display a login form

Option 1: Display login screen, redirect to desired page

  1. User clicks bookmark
  2. GET /secret -> 200, surreptitiously display login form with hidden field path="/secret"
  3. POST /processLogin -> 302 to /secret (value of path parameter)
  4. GET /secret -> 200, secret resource displayed

Analysis: Hopefully, your client is a modern browser, non-compliant with HTTP, such that it performs a GET after a 302'd POST. This applies across the board. Should I be worried?

Option 2: Redirect to login screen, redirect to desired page

  1. User clicks bookmark
  2. GET /secret -> 302 to /login
  3. GET /login via redirect -> 200, login form displayed with hidden field path="/secret"
  4. POST /processLogin -> 302 to /secret
  5. GET /secret -> 200, secret resource displayed

Analysis: Same problems as above. Added problem that the URL displayed by the browser during login changes, which is confusing to the user and breaks bookmarking, link sharing, etc.

Option 3: Display login screen, display desired page

  1. User clicks bookmark
  2. GET /secret -> 200, surreptitiously display login form with action="/secret"
  3. POST /secret -> 200, secret resource displayed

Analysis: Sadly, the refresh button is now also broken: refresh will cause the user agent to re-POST with a warning, instead of re-GETing /secret. They user gets a warning, but if they ignore it, something bad happens.

On the bright side, you minimize roundtrips with this technique.

Option 4: Redirect to login screen, display desired page

  1. User clicks bookmark
  2. GET /secret -> 302 to /processLogin
  3. GET /processLogin via redirect -> 200, login form displayed with action="/secret"
  4. POST /secret -> 302 to /secret
  5. GET /secret -> 200, secret resource displayed

Analysis: Same problems as options 2+4.

Option 5: ???

Is there another technique I'm missing?

In general, which of these techniques would you recommend?

See Also

What is correct HTTP status code when redirecting to a login page? What kind of HTTP redirect for logins? HTTP response with redirect, but without roundtrip?

like image 672
mickeyreiss Avatar asked Feb 26 '13 23:02

mickeyreiss


People also ask

What is a login redirect?

Description. Page to which users are automatically redirected after completing a successful authentication.

How do I redirect a URL after login?

The most common ways to implement redirection logic after login are: using HTTP Referer header. saving the original request in the session. appending original URL to the redirected login URL.

When an HTTP response indicates a redirection which header defines the URL the client should be redirected to?

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.

How do you handle redirects?

Avoid chained redirects: one redirect should not forward to another redirect. Redirect to the preferred version of your website, using the right protocol (http or https), domain name (www or non-www) and path notation (with or without trailing slash). Use a 302 redirect for inactive campaigns.


1 Answers

Option 1 & 3 are not following the HTTP RFC as "surreptitiously display login form" contradicts 200 GET response, where "an entity corresponding to the requested resource is sent in the response" is expected.

Option 2 is OK. All modern browsers support 302 on POST and many REST-based frameworks (like RoR) actively use it. Alternatively in "302 to /login" you can already create the session (cookie) and store the URL in session, to avoid passing the original URL in GET parameters. From usability standpoint, you can have an appropriate message on login page too (I think the URL mismatch is irrelevant here - you can't let the user see the content anyway).

Option 4: when you POST to /secret, HTTP RFC expects you to "accept the entity enclosed in the request as a new subordinate of the resource identified by the Request-URI in the Request-Line", but all you are doing is logging in and not creating anything new under /secret.

So following HTTP RFC, your best choice is Option 2. Actually Option 2 is also in line with POST->Redirect->GET design pattern, which helps to address the issue of unpredictability in bookmarking URLs to POST'ed resources.

like image 80
Anton Roslov Avatar answered Sep 23 '22 02:09

Anton Roslov