Login & Auth Workflows
Single-Page Application OAuth Login Using Authorization Code Grant With Sessions - Recommended
By Brian Pontarelli
This workflow is used by single-page applications using the FusionAuth OAuth login interface. The single-page application navigates away from its interface and over to FusionAuth’s OAuth interface. Once the user completes their login, FusionAuth redirects back to the single-page application. This requires that the single-page application re-initialize itself, but the browser should cache the application files and be able to restart it quickly. Below is a diagram that describes the primary components of this workflow and how they interact. Keep in mind that not every interaction is covered here, just the primary login interactions. At the bottom of the diagram is a discussion of the key steps.
For all of our examples, we use a store and a forum for the same company. The store requires a user to login to view their shopping cart and the forum requires the user to login to view forum posts. We also provide a couple of example attack vectors that hackers could use if portions of the system are compromised. These cases might be theoretical or based on known exploits such as XSS (cross-site scripting).
Diagram
Legend
() --> request/response bodies
{} --> request parameters
[] --> cookies
Explanation
- The browser requests the shopping cart single-page application from the application backend
- The application backend responds with the HTML, CSS & JavaScript of the application
- The browser loads the application and as part of the initialization process, it makes a request to the application backend to see if the user is logged in
- The application backend responds with a 404 indicating the user is not logged in
- The user clicks the login link and the browser navigates away from the single-page application to FusionAuth's OAuth 2 interface. The browser requests the OAuth 2 login page from FusionAuth with a
response_type
of code indicating that it is using the authorization code grant - FusionAuth responds with the HTML, CSS & JavaScript of the login page (including the form)
- The user inputs their credentials and clicks the submit button. The browser
POST
s the form data to FusionAuth - FusionAuth returns a redirect to the application backend's OAuth 2
redirect_uri
. This redirect includes the authorization code from FusionAuth. Also, this response includes a session id for the FusionAuth OAuth 2 interface as an HTTP cookie. This cookie is HttpOnly, which prevents JavaScript from accessing it, making it less vulnerable to theft - The browser requests the application backend's OAuth
redirect_uri
with the authorization code from FusionAuth - The application backend calls FusionAuth's OAuth 2 token endpoint with the authorization code and optionally the
client_secret
- FusionAuth verifies the authorization code and
client_secret
. It returns a 200 along with a JWT and refresh token in JSON - The application backend receives the 200 from FusionAuth and creates a server-side session and stores the User object (or JWT) in it
- The application backend returns a redirect back to the single-page application. The id of the server-side session is also written back to the browser in an HTTP cookie. This cookie is HttpOnly, which prevents JavaScript from accessing it, making it less vulnerable to theft. Additionally, all requests from the browser to the application backend will include this cookie so that the backend can retrieve the User object from the server-side session
- The browser requests the shopping cart single-page application from the application backend
- The application backend responds with the HTML, CSS & JavaScript of the application
- The browser loads the application and as part of the initialization process, it makes a request to the application backend to see if the user is logged in
- The application backend responds with a 200 and the User object (usually in JSON)
- The browser requests the user's shopping cart from the application backend via AJAX and includes the session cookie
- The application backend looks up the server-side session associated with the session cookie and extends the expiration date
- The application backend loads the User object (or JWT) from the session associated with the session cookie. The backend then looks up the user's shopping cart from the database (or similar location). Finally, the application backend returns the user's shopping cart (usually as JSON)
- A while later, the user's server-side session expires and the user clicks on their shopping cart again. The browser requests the shopping cart from the application backend via AJAX and sends the session cookie to the application backend
- The application backend attempts to load the server-side session associated with session cookie and realizes it is expired. The backend then returns a 401 indicating that the user is no longer logged in
- At this point, the application can allow the user to log in the same way they did above
- The browser requests the forum single-page application from the application backend. This is a standard SSO login that is fully supported by FusionAuth
- The application backend responds with the HTML, CSS & JavaScript of the application
- The browser loads the application and as part of the initialization process, it makes a request to the application backend to see if the user is logged in
- The application backend responds with a 404 indicating the user is not logged in
- The user clicks the login link and the browser navigates away from the single-page application to FusionAuth's OAuth 2 interface. The browser requests the OAuth 2 login page from FusionAuth with a
response_type
of code indicating that it is using the authorization code grant. Additionally, the session cookie that was set during the first login is also sent by the browser to FusionAuth - FusionAuth realizes that the user already has a session and is already logged in. Therefore, it returns a redirect to the application backend's OAuth 2
redirect_uri
. This redirect includes the authorization code from FusionAuth - The browser requests the application backend's OAuth
redirect_uri
with the authorization code from FusionAuth - The application backend calls FusionAuth's OAuth 2 token endpoint with the authorization code and optionally the
client_secret
- FusionAuth verifies the authorization code and
client_secret
. It returns a 200 along with a JWT and refresh token in JSON. **NOTE**: all of this happens without any user interaction, hence the SSO nature of this login - The application backend receives the 200 from FusionAuth and creates a server-side session and stores the User object (or JWT) in it
- The application backend returns a redirect back to the single-page application. The id of the server-side session is also written back to the browser in an HTTP cookie. This cookie is HttpOnly, which prevents JavaScript from accessing it, making it less vulnerable to theft. Additionally, all requests from the browser to the application backend will include this cookie so that the backend can retrieve the User object from the server-side session
- The browser requests the forums single-page application from the application backend
- The application backend responds with the HTML, CSS & JavaScript of the application
- The browser loads the application and as part of the initialization process, it makes a request to the application backend to see if the user is logged in
- The application backend responds with a 200 and the User object (usually in JSON)
- The browser requests the user's forum posts from the application backend via AJAX and includes the session cookie
- The application backend looks up the server-side session associated with the session cookie and extends the expiration date
- The application backend loads the User object (or JWT) from the session associated with the session cookie. The backend looks up the user's forum posts from the database (or similar location). Finally, the application backend returns the user's forum posts (usually as JSON)
- This is an attack vector where the attacker has stolen the user's session cookie. Here, the attacker requests the user's shopping cart with the stolen session cookie
- The application backend looks up the server-side session associated with the session cookie and extends the expiration date
- The application backend uses the session to look up the user's shopping cart. It responds to the attacker with the user's shopping cart contents (usually as JSON)
Security considerations
This a safe and feature rich login workflow in FusionAuth. It has the benefit that passwords are only provided directly to FusionAuth. It also has the benefit of full SSO capabilities when the user is automatically logged into the forum application by FusionAuth. The downside of this workflow is that the sessions might be shorter lived than refresh tokens, forcing the user to login more regularly. If this is the preferred behavior, than this workflow might be the best fit.
APIs used
Here are the FusionAuth APIs used in this example: