Login & Auth Workflows

Mobile Login To Backend With JWTs And Refresh Tokens

By Brian Pontarelli

This workflow is used by mobile applications using a native login form inside the app. This login form POSTs the user’s credentials (email and password) to either the backend of the application or directly to FusionAuth. If the credentials are POSTed to the backend of the application, this must in turn send the credentials to FusionAuth. 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 the mobile application examples, we only use a store app and do not provide an SSO workflow. The store requires a user to login to view their shopping cart. 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 hacked devices.

Diagram

Legend

() --> request/response bodies
{} --> request parameters
[] --> cookies
MobileStoreFusionAuthHackerInitializeLogin (inside Mobile App)Shopping cart loadJWT expiresShopping cart loadRefresh tokenexpiresRe-loginAttack vectorsStolen JWTStolen refresh tokenOpen app and renderlogin form1POST /api/login2POST /api/login3(User, Refresh Token and JWT)4(User, Refresh Token and JWT)5GET /api/load-shopping-cart(Refresh token and JWT)6(Shopping cart contents)7GET /api/load-shopping-cart(Refresh token and JWT)8POST /oauth2/token or POST /api/jwt/refresh(grant_type=refresh and refresh token)9(JWT)10(Shopping cart contents and new JWT)11GET /api/load-shopping-cart(Refresh token and JWT)12POST /oauth2/token or POST /api/jwt/refresh(grant_type=refresh and refresh token)13404 Missing14401 Not Authorized15Login same as above16GET /api/load-shopping-cart(JWT)17(Shopping cart contents)18GET /api/load-shopping-cart(Refresh token and JWT)19POST /oauth2/token or POST /api/jwt/refresh(grant_type=refresh and refresh token)20(JWT)21(Shopping cart contents and new JWT)22MobileStoreFusionAuthHacker

Explanation

  1. The user opens the application. The application initializes itself and then renders its login form
  2. The user inputs their credentials and clicks the submit button. The application POSTs the form data to the application backend
  3. The application backend calls the Login API in FusionAuth by passing in the credentials it received
  4. FusionAuth returns a 200 status code stating that the credentials were okay. It also returns the User object, a JWT and a refresh token in JSON
  5. The User object, JWT and refresh token are sent back to the application
  6. The application requests the user's shopping cart from the application backend and includes the JWT and refresh token
  7. The application backend verifies the JWT and then uses the JWT to identify the user. Once the user is identified, the backend looks up the user's shopping cart from the database (or similar location). Finally, the application backend returns the user's shopping cart contents
  8. A while later, the user's JWT expires and the user clicks on their shopping cart again. The application requests the shopping cart from the application backend and sends the JWT and refresh token to the application backend
  9. The application backend verifies the JWT and realizes it is expired. Since the browser also sent across the refresh token, the application backend calls the JWT refresh API in FusionAuth with the refresh token
  10. FusionAuth looks up the refresh token and returns a new JWT
  11. The application backend responds with the user's shopping cart contents. It also includes the new JWT that replaces the old JWT
  12. A while later, the user's refresh token expires and the user clicks on their shopping cart again. The application requests the shopping cart from the application backend and sends the JWT and refresh token to the application backend
  13. The application backend verifies the JWT and realizes it is expired. Since the application also sent across the refresh token, the application backend calls the JWT refresh API in FusionAuth with the refresh token
  14. Since the refresh token has expired, FusionAuth returns a 404 status code
  15. Since FusionAuth returned a 404 status code, the application backend returns a 401 that indicates 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. This is an attack vector where the attacker has stolen the user's refresh token. Here, the attacker requests the user's shopping cart with the stolen refresh token and an invalid JWT
  18. The application backend verifies the JWT and realizes it is invalid. Since the attacker also sent across the refresh token, the application backend calls the JWT refresh API in FusionAuth with the refresh token
  19. FusionAuth looks up the refresh token and returns a new JWT
  20. The application backend uses the JWT to look up the user's shopping cart. It responds to the attacker with the user's shopping cart. It also includes the new JWT that attacker can now use
  21. This is an attack vector where the attacker has stolen the user's JWT. Here, the attacker requests the user's shopping cart with the stolen JWT
  22. The application backend verifies the JWT and then uses the JWT to identify the user. Once the user is identified, the backend looks up the user's shopping cart from the database (or similar location). Finally, the application backend returns the user's shopping cart to the attacker

Security considerations

This workflow is a secure methods of authenticating users. It uses a JWT and refresh token that are securely store on the mobile device. 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: