> For the complete documentation index, see [llms.txt](https://fusionauth.io/docs/llms.txt)

# WebApp OAuth Login Using Resource Owner Password Credentials Grant With Sessions And Refresh Tokens | FusionAuth Docs

An explanation of webapp login using a native login form that submits to the application backend (with server-side sessions plus refresh tokens in cookies) which calls FusionAuth's Resource Owner's Password Grant

# WebApp OAuth Login Using Resource Owner Password Credentials Grant With Sessions And Refresh Tokens

By Brian Pontarelli

[Edit on GitHub](https://github.com/FusionAuth/fusionauth-site/blob/main/astro/src/content/articles/login-authentication-workflows/webapp/oauth-resource-owner-password-credentials-grant-sessions-refresh-tokens-cookies.mdx)

[View Markdown](https://fusionauth.io/articles/login-authentication-workflows/webapp/oauth-resource-owner-password-credentials-grant-sessions-refresh-tokens-cookies.md)

This workflow is used by web applications using the FusionAuth OAuth login interface. The web application navigates over to FusionAuth and then FusionAuth redirects back to the web application at the end of the OAuth workflow. 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
```

```mermaid
sequenceDiagram
  autonumber
  participant Browser
  participant Store
  participant Forums
  participant FusionAuth
  participant Hacker
  Note over Browser,Hacker: Initialize
  Browser->>Store: GET /
  Store->>Browser: (HTML, CSS & JavaScript - with login link)

  Note over Browser,Hacker: Login (inside WebApp)
  Browser->>Store: GET /login
  Store->>Browser: (Login form HTML)
  Browser->>Store: POST /login
  Store->>FusionAuth: POST /oauth2/token<br/>(grant_type=password)
  FusionAuth->>Store: (Refresh Token and JWT)
  Store->>Store: Create session and store User in it
  Store->>Browser: 302 Location: /shopping-cart<br/>[SessionId and Refresh token HttpOnly w/ domain: store.example.com]

  Note over Browser,Hacker: Shopping cart load
  Browser->>Store: GET /shopping-cart<br/>[SessionId and Refresh token HttpOnly w/ domain: store.example.com]
  Store->>Store: Session extended
  Store->>Browser: (Shopping cart HTML)

  note over Browser, Browser: Session expires<br/>Refresh token still valid
  
  Note over Browser,Hacker: Shopping cart load
  Browser->>Store: GET /shopping-cart<br/>[SessionId and Refresh token HttpOnly w/ domain: store.example.com]
  Store->>FusionAuth: POST /oauth2/token or POST /api/jwt/refresh<br/>(grant_type=refresh and refresh token)
  FusionAuth->>Store: (JWT)
  Store->>Store: Create new session and store User in it
  Store->>Browser: (Shopping cart contents)<br/>[New SessionId HttpOnly w/ domain: store.example.com]

  note over Browser: Session expires<br/>Refresh token expires
  
  Note over Browser,Hacker: Re-login
  Browser->>Store: GET /shopping-cart<br/>[SessionId and Refresh token HttpOnly w/ domain: store.example.com]
  Store->>FusionAuth: POST /oauth2/token or POST /api/jwt/refresh<br/>(grant_type=refresh and refresh token)
  FusionAuth->>Store: 404 Missing
  Store->>Browser: 302 Location: /login
  Browser->>Browser: Login same as above

  Note over Browser,Hacker: SSO login to forums - not provided by FusionAuth for this workflow

  Note over Browser,Hacker: Initialize
  Browser->>Forums: GET /<br/>[No cookies]
  Forums->>Browser: (HTML, CSS & JavaScript - with login link)

  Note over Browser,Hacker: Login (inside WebApp)
  Browser->>Forums: GET /login
  Forums->>Browser: (Login form HTML)
  Browser->>Forums: POST /login
  Forums->>FusionAuth: POST /oauth2/token<br/>(grant_type=password)
  FusionAuth->>Forums: (Refresh Token and JWT)
  Forums->>Forums: Create session and store User in it
  Forums->>Browser: 302 Location: /posts<br/>[SessionId and Refresh Token HttpOnly w/ domain: forums.example.com]

  Note over Browser,Hacker: Forum load
  Browser->>Forums: GET /posts<br/>[SessionId and Refresh token HttpOnly w/ domain: forums.example.com]
  Forums->>Forums: Session extended
  Forums->>Browser: (Forum posts HTML)

  Note over Browser,Hacker: Attack vectors

  Note over Browser,Hacker: Stolen refresh token
  Hacker->>Store: GET /shopping-cart<br/>[Refresh token and bad session id HttpOnly w/ domain: store.example.com]
  Store->>FusionAuth: POST /oauth2/token or POST /api/jwt/refresh<br/>(grant_type=refresh and refresh token)
  FusionAuth->>Store: (JWT)
  Store->>Store: Create session and store User in
  Store->>Hacker: (Shopping cart HTML)<br/>[New JWT HttpOnly w/ domain: store.example.com]

  Note over Browser,Hacker: Stolen session id
  Hacker->>Store: GET /shopping-cart<br/>[SessionId HttpOnly w/ domain: store.example.com]
  Store->>Store: Session extended
  Store->>Hacker: (Shopping cart HTML)
```

## Explanation

1.  The browser requests the shopping cart webapp's homepage from the application backend
2.  The application backend responds with the HTML, CSS & JavaScript of the homepage
3.  The user clicks the login link and the browser requests the login page from the application backend
4.  The application backend responds with the HTML, CSS & JavaScript of the login page (including the form)
5.  The user inputs their credentials and clicks the submit button. The browser `POST`s the form data to the application backend
6.  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
7.  FusionAuth returns a 200 status code stating that the credentials were okay. It also returns a JWT and a refresh token in JSON
8.  The application backend receives the 200 from FusionAuth and creates a server-side session and stores the User object (or JWT) in it
9.  The application backend returns a redirect to the browser instructing it to navigate to the user's shopping cart. The id for the server-side session is written back to the browser in an HTTP cookie. The refresh token from FusionAuth is also written back to the browser in an HTTP cookie. These cookies are HttpOnly, which prevents JavaScript from accessing them, making them less vulnerable to theft. Additionally, all requests from the browser to the application backend will include these cookies so that the backend can retrieve the User object from the server-side session and refresh their session if it expires
10.  The browser requests the user's shopping cart from the application backend and includes the session and refresh token cookies
11.  The application backend looks up the server-side session associated with the session cookie and extends the expiration date
12.  The application backend loads the User object (or JWT) from the server-side session. 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 as HTML, CSS & JavaScript that the browser renders
13.  A while later, the user's session expires and the user clicks on their shopping cart again. The browser requests the shopping cart from the application backend and sends the session id and refresh token cookies to the application backend
14.  The application backend attempts to load the server-side session associated with session cookie 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
15.  FusionAuth looks up the refresh token and returns a new JWT
16.  The application backend receives the 200 from FusionAuth and creates a server-side session and stores the User object (or JWT) in it
17.  The application backend responds with the user's shopping cart HTML, CSS & JavaScript that the browser renders. It also includes the new session id as a cookie that replaces the old session id in the browser
18.  A while later, the user's server-side session and refresh token both expire and the user clicks on their shopping cart again. The browser requests the shopping cart from the application backend and sends the session and refresh token cookies to the application backend
19.  The application backend attempts to load the server-side session associated with session cookie 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
20.  Since the refresh token has expired, FusionAuth returns a 404 status code
21.  Since FusionAuth returned a 404 status code, the application backend returns a redirect to the browser that sends the user to the login page
22.  The user can log in the same way they did above
23.  The browser requests the forum webapp's homepage from the application backend. This is a standard SSO login, but because of the way this workflow manages cookies and identities, FusionAuth does not provide SSO capabilities automatically
24.  The application backend responds with the HTML, CSS & JavaScript of the homepage
25.  The user clicks the login link and the browser requests the login page from the application backend
26.  The application backend responds with the HTML, CSS & JavaScript of the login page (including the form)
27.  The user inputs their credentials and clicks the submit button. The browser `POST`s the form data to the application backend
28.  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
29.  FusionAuth returns a 200 status code stating that the credentials were okay. It also returns a JWT and a refresh token in JSON
30.  The application backend receives the 200 from FusionAuth and creates a server-side session and stores the User object (or JWT) in it
31.  The application backend returns a redirect to the browser instructing it to navigate to the user's forum posts. The id for the server-side session is written back to the browser in an HTTP cookie. The refresh token from FusionAuth is also written back to the browser in an HTTP cookie. These cookies are HttpOnly, which prevents JavaScript from accessing them, making them less vulnerable to theft. Additionally, all requests from the browser to the application backend will include these cookies so that the backend can retrieve the User object from the server-side session and refresh their session if it expires
32.  The browser requests the user's forum posts from the application backend and includes the session and refresh token cookies
33.  The application backend looks up the server-side session associated with the session cookie and extends the expiration date
34.  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 forum posts from the database (or similar location). Finally, the application backend returns the user's forum posts as HTML, CSS & JavaScript that the browser renders
35.  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 session id
36.  The application backend verifies the session id and realizes it is invalid. Since the browser also sent across the refresh token, the application backend calls the JWT refresh API in FusionAuth with the refresh token
37.  FusionAuth looks up the refresh token and returns a new JWT
38.  The application backend receives the 200 from FusionAuth and creates a server-side session and stores the User object (or JWT) in it
39.  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 HTML, CSS & JavaScript. It also includes the new session id as a cookie that attacker can now use
40.  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
41.  The application backend looks up the server-side session associated with the session cookie and extends the expiration date
42.  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 HTML, CSS & JavaScript

## 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:

*   [/oauth2/token (grant)](https://fusionauth.io/docs/apis/oauth/token.md#resource-owner-password-credentials-grant-request)
*   [/oauth2/token (refresh)](https://fusionauth.io/docs/apis/oauth/token.md#refresh-token-grant-request)
*   [/api/jwt/refresh](https://fusionauth.io/docs/apis/jwt/refresh-a-jwt.md)