Login & Auth Workflows

Single-Page Application OAuth Login Using Resource Owner Password Credentials Grant With Sessions

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
BrowserStoreForumsFusionAuthHackerInitializeLogin (inside SPA)Shopping cart loadSession expiresRe-loginSSO login to forums - not provided by FusionAuth for this workflowInitializeLogin (inside SPA)Forum loadAttack vectorsStolen session idGET /1(SPA HTML, CSS & JavaScript)2AJAX GET /api/user[No cookies]3404 Missing4Render login form5AJAX POST /api/login6POST /oauth2/token(grant_type=password)7(Refresh Token and JWT)8Create session andstore User in it9[SessionId HttpOnly w/ domain: store.example.com]10AJAX GET /api/load-shopping-cart[SessionId HttpOnly w/ domain: store.example.com]11Session extended12(Shopping cart contents)13AJAX GET /api/load-shopping-cart[SessionId HttpOnly w/ domain: store.example.com]14401 Not Authorized15Login same as above16GET /[No cookies]17(SPA HTML, CSS & JavaScript)18GET /api/user[No cookies]19404 Missing20Render login form21AJAX POST /api/login22POST /oauth2/token(grant_type=password)23(Refresh Token and JWT)24Create session andstore User in it25[SessionId HttpOnly w/ domain: forums.example.com]26AJAX GET /api/load-posts[SessionId HttpOnly w/ domain: forums.example.com]27Session extended28(Forum posts)29GET /api/load-shopping-cart[SessionId HttpOnly w/ domain: store.example.com]30Session extended31(Shopping cart contents)32BrowserStoreForumsFusionAuthHacker

Explanation

  1. The browser requests the shopping cart single-page application from the application backend
  2. The application backend responds with the HTML, CSS & JavaScript of the application
  3. 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
  4. The application backend responds with a 404 indicating the user is not logged in
  5. The application renders the login form
  6. The user inputs their credentials and clicks the submit button. The browser AJAX POSTs the form data to the application backend
  7. The application backend calls the OAuth token endpoint in FusionAuth by passing in the credentials it received plus a grant_type of password, which indicates it is using the resource owner password credentials grant in FusionAuth's OAuth 2 backend
  8. FusionAuth returns a 200 status code stating that the credentials were okay. It also returns a JWT and a refresh token in JSON
  9. The application backend receives the 200 from FusionAuth and creates a server-side session and stores the User object (or JWT) in it
  10. The application backend might return the User object to the browser if it needs it. 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
  11. The browser requests the user's shopping cart from the application backend via AJAX and includes the session cookie
  12. The application backend looks up the server-side session associated with the session cookie and extends the expiration date
  13. 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)
  14. 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
  15. 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
  16. At this point, the application can allow the user to log in the same way they did above
  17. The browser requests the forums single-page application from the application backend. This is a standard SSO login that is fully supported by FusionAuth
  18. The application backend responds with the HTML, CSS & JavaScript of the application
  19. 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
  20. The application backend responds with a 404 indicating the user is not logged in
  21. The application renders the login form
  22. The user inputs their credentials and clicks the submit button. The browser AJAX POSTs the form data to the application backend
  23. The application backend calls the OAuth token endpoint in FusionAuth by passing in the credentials it received plus a grant_type of password, which indicates it is using the resource owner password credentials grant in FusionAuth's OAuth 2 backend
  24. FusionAuth returns a 200 status code stating that the credentials were okay. It also returns a JWT and a refresh token in JSON
  25. The application backend receives the 200 from FusionAuth and creates a server-side session and stores the User object (or JWT) in it
  26. The application backend might return the User object to the browser if it needs it. 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
  27. The browser requests the user's forum posts from the application backend via AJAX and includes the session cookie
  28. The application backend looks up the server-side session associated with the session cookie and extends the expiration date
  29. 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)
  30. 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
  31. The application backend looks up the server-side session associated with the session cookie and extends the expiration date
  32. 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 workflow is one of the more secure methods of authenticating users. One downside is that the application backend receives passwords from the browser. While this isn’t an issue if TLS is used and the passwords are not stored by the application backend, developers that do not want to be part of the password chain of responsibility should consider other workflows.

APIs used

Here are the FusionAuth APIs used in this example: