Access Tokens, Refresh Tokens, And User Data - reactjs

I am using a JWT authentication scheme for my app. I did some research about how to store and use access and refresh tokens, and I have several questions that I couldn't really find an answer to. For the app, I am using React for the frontend and .NET 6 Web API for the backened.
Question 1: Storing what where?
Based on the research I did, local storage is not a good place to store a jwt token for security reasons. So probably the second best alternative would be HttpOnly cookie for the jwt token and local storage for the refresh token. However I did read some articles where jwt token is stored in local storage while the refresh token is stored as HttpOnly cookie. Which approach is better, and the pros and cons of each. P.S I will be rotating the tokens, i.e a new access and refresh token will be generated once the old jwt token is refreshed. Or even store it in memory such as redux state
Question 2: When to refresh JWT Token?
Should the jwt token be refreshed just before it expires, such that the backend can verify the token, or is it fine to refresh the token after it expires (by bypassing the verificatoin when refreshing the token only i.e the refresh endpoint). Also should refreshing, be done by setting an timer/interval, or waiting for a request to fail?
Question 3: Accessing User Data and Expiry Date
I am storing some user data, such as username and password in the jwt token so I can acees them in the frontend. The problem is that when setting the jwt token as HttpOnly cookie, since Javascript can't access the token, I won't be able to access user data and the token's data(such as jti and expiry date). For the user data, I could do a seperate request to access user data such as username and email, but for the JWT token's expiry date, how could I obtain it?
I would appreciate answers to these questions or any feedback if someone faced similar issues and how you resolved them

Consider these as discussion rather then guideleines
Question 1: Storing what where?
Storing access tokens in memory is a good choice
But if you have a refresh token, and you need to do a silent login, local storage is the only choice
but you can always encrypt the token before storing
Question 2: When to refresh JWT Token?
if you wait for token to expire and then refresh with refresh token then existing request which failed with expired token need to be queued again.
if you refresh token on regular intervals, if existing token is invalidated with refreshing, then again the same issue failing requests needing to be queued again.
if you are using axios, you can use libraries like axios-auth-refresh, which will queue the failed requests and try then again with a new token.
you can check their source code or may be create your own version if handling failed calls is important.
Question 3: Accessing User Data and Expiry Date
Access token and cookies should not contain sensitive information
its better to make another call to the api to get users info

Question 1: Storing what where?
First, it is never recommended to use refresh tokens if you are not able to store them securely. Consider building a traditional web app instead.
Second, session storage is always recommended over local storage for these types of tokens.
However, I understand the problem and there are ways to get around this with “Secure SameSite Cookies” if both your apps use the same domain name. OWASP has recommendations, have a look at “token side jacking”: https://cheatsheetseries.owasp.org/cheatsheets/JSON_Web_Token_for_Java_Cheat_Sheet.html
A simplified version below (please read OWASP recommendation and make the necessary adjustments):
During the authentication face (Web API):
create a “user context”, a random string
set access token with “user context”
set refresh token with “user context”
set http response header with a hardened cookie (flags: HttpOnly + Secure + SameSite + cookie prefixes). Value: “user context”
You need to implement validation of “user context” for API requests and for the refresh token flow; if “cookie user context” does not match “token user context”, then respond with proper http error code.
This makes it possible to:
store access token in session storage
store refresh token in local storage
Question 2: When to refresh JWT Token?
Should the jwt token be refreshed just before it expires, such that the backend can verify the token, or is it fine to refresh the token after it expires (by bypassing the verificatoin when refreshing the token only i.e the refresh endpoint).
If access token has expired then try refreshing tokens using your refresh token. If refresh token has expired, then a new authentication is needed. The definition of an expired token is that it is no longer valid and cannot be used.
Also should refreshing, be done by setting an timer/interval, or waiting for a request to fail?
Wait for the request to fail. If both access token and refresh token has expired, then a new authentication is needed.
Question 3: Accessing User Data and Expiry Date
It is not recommended to store sensitive information in access token. The access token should be opaque to the client application. Set access token with some identifier and create a /userinfo endpoint that returns information about the user. Eg, Create an authController with two actions:
/token (used for authentication)
/userinfo (used for retrieving information about the user)

Related

Refreshing token with on-behalf-of flow (single-sign-on with Teams)

I have a single-sign-on scenario with Microsoft Teams. See full description in the documentation: https://learn.microsoft.com/en-us/microsoftteams/platform/tabs/how-to/authentication/auth-aad-sso
I am getting an access token by "trading" the "teams" token for an access token.
My question is, how do I refresh this access token? In single-sign-on scenario the "refrehs_token" is not returned (?), so normal OAuth2 refresh flow does not seem to be possible.
Imagine I traded it once, and got the access token that expires in say 2 hours. I use it to access graph API (or whatever), and then the token expires.
What should I do to get a new access token? Can I just ask Teams for a fresh "teams" token and trade it again in case the old one expired? Teams App takes care of refreshing its own tokens, right? When should I do this (when I get "access denied", or just if I see that the token has expired?
Looks like I found the reason - you must pass offline_access as scope request then you get back the refresh_token. That was my issue actually, and it is documented, I just did not read carefully:
https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-on-behalf-of-flow
refresh_token The refresh token for the requested access token. The calling service can use this token to request another access token after the current access token expires. The refresh token is only provided if the offline_access scope was requested.

How to use refresh token coming from acquiretoken silent in MSAL-browser

I am trying to acquire token by aquiretokensilent after login and then have to do authorization in multiple modules.As documentation of MSAL-browser acquiretokensilent will automatically take care of refresh token.In network tab also i am able to see refresh token.But how to use it, does it automatically replace access token or do i need to do something extra and how i can see that refresh token in the console converting to access token after expiry of access token.I have read lot of documents but not got clearity how to use it.
A refresh token is used for renewing an access token or request access tokens with other scopes.
This official doc indicated that how a refresh token renews/requests a new access token and a new refresh token at the base layer.
And yes, you should call aquiretokensilent before API call, if the access token exists and it is not expired, this function will reply the access token to you from local cache directly, if not, it will request a new access token by refresh token from Azure AD.
For details, see this doc.

Bearer Token authentication and JWT

I've been provided with a REST API which has authentication type bearer (Security Scheme Type: API Key, Header parameter name: Authorization) and which i use to authenticate the user and then fetch other data (i will only create the front end using react).
As a first step the user logs in and i sent his/her username-password to the prementioned REST API and get back an access and a refresh token.
Is anything wrong with storing these 2 tokens in a cookie in order to use them in subsequent requests? How does JWT comes into play regarding these 2 tokens? Is JWT of any use to me in this situation?
There's nothing wrong in storing the tokens in cookies, but if you're planning to have a Single Page Application with React it should be enough to store these tokens in memory. Once the user refreshes the page you can either make them sign in again or perform a silent login in the background to get a new set of tokens. In both cases the session kept on the Authorization Server should kick in and you should get new tokens without the need of user interaction.
Your tokens will be much safer if you don't keep them in cookies.
JWTs are not a requirement for access and refresh tokens. If you don't have to use them I would recommend going with opaque tokens. That said, since you do not have control over the API you might be limited to the format required by the API. If you don't want to be limited by this format you can set up your own gateway which you can use to perform token exchange or introspection and forward requests to the API with proper tokens (something which is called a Phantom Token pattern.
From my understanding of the question, you are using an identity provider which provides you with access token and refresh token for the users. That means it is a authentication as a service REST API at works here.
The REST API requires an authorisation header to be passed along with the username-password to exchange for access token and refresh token for the users. (correct me if I'm wrong) In this case, you might want to keep the authorisation header away from the users (consult the authentication as a service documentation).
You call the REST API with payloads (the user-password) along with headers like this:
Authorization: ACCESS_TOKEN
However the ACCESS_TOKEN is the one provided by the vendor for you to use the REST API. On success call of the REST API, it should return you with a set of access token and refresh token. You can then use this access token and refresh token to safe guard your own API, API that you control to provide service to your users.
The access token and refresh token might just be JWT tokens (again consult the vendor documentation).
Also if you are using an authentication as a service REST API, check the documentation if they provide a client sdk. In that case, it should show you the best practise of handling the access token and refresh token it returned.

What is the flow of using JWT work on the frontend?

I am new to web dev. I built a backend using Django Rest Framework and am using JWT to handle auth.
Now, I want to connect my backend to my frontend in React. But, I am confused how this should be done. Here are my question:
What is the whole flow of requesting and using JWT access and refresh tokens? Like, when should I request a new access token with my refresh token and when should I request a new refresh token? Thanks!
I will make a quick response:
Flow of requesting and using JWT:
A picture worth a thousand words.
The access token is not lasting forever. Whenever it expires, you have to request a new access token with your refresh token.
Refresh tokens can expire, although their expiration time is usually much longer than access tokens. To handle this case, almost all implementations I've seen return a known error code of 'invalid_grant' that you can check for on the client-side and handle by your business. (ex: Show login page...)
Regarding your questions:
What is the whole flow of requesting and using JWT access and refresh tokens?
I don't know you're using what's package about JWT, having too many packages about Django JWT on github (pyjwt, djangorestframework_simplejwt, ...). And Im using pyjwt in my application, because I want to custom my authentication in-app for security.
The workflow:
When FE send request to login/signup APIs, BE generate a token by using JWT, and return that token in the response.
FE store that token on local storage, using it for sending other requests.
BE will take the token by each request from FE to verify. The same as TokenAuthentication of DRF, we must be custom it when using pyjwt. Will verify the JWT token instead.
when should I request a new access token with my refresh token and when should I request a new refresh token?
You can request a new access token after that token is expired.
When you're using djangorestframework_simplejwt you can see the refresh token but in my case (pyjwt), I just need re-generate jwt token again :)
There could be options, but simple flow is next:
You do auth and get access and refresh tokens from a backend and save them as cookies.
You use your access token until you get error 401 because access token has expired
Then you try to refresh your tokens using your refresh token. If you use axios on frontend, good option to write a middleware for this case. This middleware will refresh tokens and repeat a last request. There should be recipes in google.
If success you got new pair of access and refresh tokens and continue your workflow.
If fail, you need to auth again to get tokens.

OAuth2 grant for interacting between my Angular app and my REST API?

Help me pick the right OAuth2 grant type for my Angular App and my REST API?
UX-wise I want just one login form on my front-end, that would ask for username/pass(no dialog asking for permissions). I think the "Resource Owner(Password) Grant" is the most appropriate for me(since I control front&backend), but I'm not sure how should I handle access token refresh.
Correct me if I wrong about the flow:
When user submits credentials through login form, access token is returned.
I can store this token in LocalStorage to make subsequent Ajax requests with it.
As I understand access tokens should be short-lived. And should be updated with Refresh token. Should the refresh token be returned with the access token after initial login and also stored on the client? If not what is the alternative?
Should there be any session maintained on the server to invoke access token refresh? or I should make calls from front-end to refresh the access token when it is about to expire. But then I need a refresh token on the front-end, right?
As you see there is a mess in my head about refresh token. Would be great to have some clarification or suggestion for another grant implementation.
Backend technology I guess is irrelevant here, but just in case it's Symfony2 with FOSOAuthServerBundle.
When you are calling the TOKEN endpoint (for every grant_type possible) on a OAuth Server, you get an access_token but other information as well (I think there are all here):
{
access_token: // your short-lived token
expires_in: // number of seconds before the access_token is invalid
token_type: // the type of the access_token
scope: // scopes of the access_token
refresh_token: // long-lived token to get a new access_token
}
You need, in my opinion, all these information (maybe the scope is unused, but all others will be used later). You have to store the access_token to ba able to make API calls. After seconds, your access_token will not work anymore. You will need to get a new one. You can either ask the user to log in AGAIN or use the refresh_token.
You will have to call the OAuth Server on the TOKEN endpoint but with a grant_type: refresh_token. You will have to provide the refresh_token from the first request (among other information) and in return you will have the same response as above. In fact, I think you will have to do that every time an access_token is expired. In my opinion, the server side does not know anything about sessions or connected users. It knows about valid and invalid access_token.
This is OAuth. If you don't want to have to refresh everytime, you can make a long-lived access_token (by setting the expires_in), I think this is the only solution that makes sens in an OAuth context.
Do you need some clarification about OAuth in general?

Resources