Reference token as an identifier to the access token stored in identity server. What is the best practice to manage it?
There was a claim changed, how to update the access token to reflect
the change. I found that the current access token doesn't get updated automatically for that case so would like to know how to achieve that claim update on the access token.
What is the suitable lifetime it should have (15 days or more?), once expired to
re-issue it with a refresh token or just getting the end user to
login again?
Does it need to be validated through the introspection endpoint from
the javascript client (Angular) at all? I know the API needs to have a back
channel to validate it just unsure about the javascript side.
To get automatic refresh token management, I would recommend that you use the IdentityModel library from the authors of IdentityServer.
You can set the UpdateAccessTokenClaimsOnRefresh flag to true in the client definition, then you will get updated claims when you refresh the access token.
For dealing with tokens in the browser, I would recommend watchin this video
alert‘OAuth 2 0’; // The impact of XSS on OAuth 2 0 in SPAs
then visit the Backend for Frontend (BFF) Security Framework library.
Related
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)
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.
I have an implementation of IdentityServer4 which connects with Azure AD for authentication (OIDC). In the callback method, using the IdentityServertools, I am generating the access_token and redirecting the user to SPA with the same. The SPA then stores the access_token into localstorage and uses it for authentication.
Normally, when my SPA app hits the token endpoint of the IdentityServer4, it gives access_token and refresh_token and then uses refresh_token to re-authenticate a returning user.
In this case of SSO with Azure AD, do I need to generate refresh_token manually? If yes, I can build on top of default implementation and that's not the problem (However, the docs suggest against of changing the IRefreshTokenService implementation or building something from scratch)
My real question is, is there a need of refresh_token here? Because refresh_tokens are stored in DB and never get's deleted and after sometime, these refresh_tokens table will swell (right now it already has 80k rows). The user is expected to click on a small tile inside SAP's Successfactor - that will open the signin/consent screen of Azure or will directly take the user to the main page where zhe will just answer a question and done. So it's hardly 2-3 mins business. So I can continue to generate access_tokens from my IdentityServer4 for every click as I don't expect the user to stay authenticated in the browser if zhe has logged out from SAP's Successfactor (or any other app linked with Azure).
Please advise, if I should generate refresh_token? Is it a good architecture?
Access token is used to prove the request is allowed to access the resource(such as api from ms or your custom api) and refresh token is used to refresh access token to make sure the access token isn't expired. Access token will expire in an hour by default and refresh token has 90 days.
At this point, we can easily find the refresh token is designed for some special scenarios because the expired time for refresh token is much longer than access token's expired time, but we can also generate a new access token in other way such as using msal or sign in again.
As you said in the question, you can generate an access token by one click and you don't expect users to stay authenticated for a long time. So I think it's unnecessary for you to use refresh token.
I am using token based security in my web app. The server side is wrote using c# and i am using openiddict for logging in and issuing tokens, found here. I am currencyly using Implict flow.
By default my tokens have a lifespan of 1 hour, after that you have to logging again. I have locked down my API to accept bearer tokens only and not cookies.
I wanted to implement refresh tokens but after reading many websites, it appears that implementing refresh tokens on a web app, is not a good way to go due to a hacker getting the refresh token. I know that to use refresh tokens, you must use code flow, instead of implict, which i can do.
How do people get round this situation in their web apps? I cant be the only one who wants a token to last longer than an hour in a web app?
The approach recommended by OpenID Connect is to send an authorization request in a hidden frame with the same parameters as the ones you use for the initial implicit flow request plus prompt=none and optionally, an id_token_hint corresponding to the id_token you extracted from the authorization response.
When using prompt=none, the identity provider won't display any consent form and will directly redirect the user agent to the redirect_uri you specify, with the new token appended to the URI fragment, just like for a classic implicit flow request. You can retrieve it by extracting it from the popup.location.hash property.
If the request cannot be processed (invalid request, unauthenticated user, invalid id_token_hint, consent required, etc.), an error is returned and the identity provider either redirects the user agent to the redirect_uri with an error parameter or stops processing the request.
Note that due to the same origin policy, you can't access popup.location.hash if the current location belongs to a different domain (e.g if the identity provider refuses to redirect the user agent to your client app): it will throw an access denied exception. In this case, it's always better to add a timeout to your "refresh" operation.
Sadly, there are very few libraries that can help you with this task. oidc-token-manager is one of them, but it has a few limitations that will prevent it from working OTB with OpenIddict: it doesn't support raw RSA keys (you have to explicitly use a X509 certificate in the OpenIddict options) and it doesn't send the id_token_hint parameter required by OpenIddict when sending a prompt=none request.
I am building a glass app using the PHP sample app as reference.
To my understanding, the glass app is a web app which is user facing. When the user visit the web app, they will authorize the web app (using oauth2) to access their resources, and once authorization succeeded the web app will get an access token, which is then saved in a sqlite database (there's this store_credentials() function which stores the access token).
So if I have 100 users who visit the web app and register, the database will hold 100 access tokens for these users. Let's say I have some backend code which pull from a RSS feed every hour, and whenever I find there's a new story I will push it to all registered users. Let's say I have a cron job which does this, when when this job is triggered, I will find all the access tokens in the database and use them to make mirror API calls to insert cards. But what if some of the access token is expired when I am trying to make the mirror API call? It seems I will need to ask user to re-authorized, but at this point I am not interacting with the user. If I have a refresh token, I may be able to call oauth again to get a new access token.
Thanks.
You pretty much answered your own question - when you request permission using OAuth, you should also request "offline" access. The first time you do this for each user it will give you a refresh token along with your access token, and you should store both. If you did not request offline access initially, you will need to revoke the tokens that have been granted and re-grant them with offline access.
If the sample app you're referring to is the one at https://github.com/googleglass/mirror-quickstart-php, all this should be done for you already with the libraries included. The credentials returned from $client->getAccessToken() in oauth2callback.php should include both the access and refresh tokens, and these are saved in that same file by calling store_credentials(). The client libraries should check if the access token has expired and, if so, it gets a new one with the refresh token before making the call.
You may want to take a look at the contents of the credentials object at these various points and make sure there is a refresh token. If not, try revoking all the tokens and starting again, since it sounds like the first time you authorized the client you did so without requesting offline access.
If you are doing this yourself, best practice is to either refresh the access token if it has expired or is about to expire (since there may be some delay) before use, or (even better) attempt to make the call with an access token and, if it fails with an authentication error, get a new access token via the refresh token and try again.