Refreshing OAuth2 Access Token - oauth-2.0

I am building web application which will consist of backend and frontend (web) part. I want to introduce auth between these two parts and my intention is to use OAuth2 for that.
Frontend part will act as OAuth Client, and backend will serve as OAuth Provider - so backend will be issuing access and refresh token.
My plan is to store refresh token of course on backend side, and to store access token on frontend side (and send access token with each request as header parameter). Lets say that access token last for 24h and refresh token last for 3 months.
My question is when (and how) should I refresh access token which is stored on frontend side? (I am asking this because I want to refresh it before it is expired; do not want to face user with login flow if it is not necessary)
Should I return new access token after each successful request and store it on frontend side (does not sound as a good idea)
Should I return new access token if existing one is just to be expired - probably need to check on frontend side if new access token is returned through header parameters and if it so to replace old one.
Should I store both access and refresh token on Frontend Side and if access token is expired then get new one using refresh token
Something else?
I am not sure what is the best practice.

No 3 is the best case I think.
If you store both tokens (access_token & refresh_token) on frontside using by cookie, you can easily check from request using getCookie method.
check access token from request
if (isAccessTokenExpired) check refresh token from request
if (isRefreshTokenExpired) LoginRequiredException(custom excpetion and do something)
else refresh both tokens(extend time or create new token) and response setCookie
else just go on.

Related

Clarification needed on why Client application should need both idtoken and access token

Client application fetches the idtoken for authentication. But for the resource server, it needs to again make a call to Auth server and fetch the access token. Hence, does it make sense to make two calls for every oauth2.0 flow. The access token is what will be sent to the resource server. Am I missing something here.
With OpenID Connect, the ID-token is returned to the client at the same time as the access-token. So there is no specific need to make two requests to get the two tokens.
If you ask for an refresh token as well, then that one will also be returned at the same time.
The API (Resource Server) only receives access tokens from the client and it can without asking the identity provider validate the token. The API does not receive any ID-token.

How does a client using Owin/Katana/OIDC use a Refresh Token?

I have an ASP.net MVC web application that uses Microsoft's Owin middleware (Microsoft.Owin.Security.OpenIdConnect) to configure OpenID Connect authentication. My identity provider (Okta) is configured to support refresh tokens and I have confirmed that it is working. When signing in, my application receives an Access, ID and Refresh Token as expected. These tokens are validated and returned to the client in a cookie called ".AspNet.Cookies" (the default). On each request, the cookie and these tokens are parsed into a set of claims. Great so far. 👍
The Owin (Katana) middleware does not appear to do anything further with the Refresh Token, so I have implemented a token client to request a new Access Token from my IdP using the Refresh Token. This is working as expected. 👍
Two questions:
When and where should the application check to see if the Access Token is expired and request a new one?
After receiving new a access, id, and refresh token, how and where should the application update the user identity, claims and cookie?
OWIN COOKIE UPDATES
I believe the comment at the end of this post has the type of code you can write - I remember using similar code a few years back.
With OWIN you are using a server side stack secured by cookies so I'm not sure where access tokens are actually used, but maybe one of these is true?
The C# back end uses tokens to call an API
The Web UI downloads tokens from the web back end and makes Ajax calls to an API
PATTERN FOR HANDLING EXPIRED TOKENS
The only reliable pattern to handle expiry is to do this in the API client code:
When you get a 401 response from the API
Try to refresh the token and retry the API call with a new access token
If you can't refresh the token, redirect the user to sign in again
I always implement this with 2 classes, as in this SPA code of mine:
ApiClient - handles API calls
Authenticator - handles OAuth calls
If the Web UI is getting tokens from the web back end and then calling an API, your web back end could provide MVC operations similar to those in my authenticator class:
getAccessToken - get the current access token, though it may fail with a 401
refreshAccessToken - use this if a 401 is received and you need a new token
TOKEN EXPIRY TIMES
It is also possible to check token expiry times in the background - to reduce the number of client 401s. This is not a full solution however, since 401s can occur for other reasons in addition to expiry.

Why refresh token has to be replaced when used?

I see most of people saying when we use refresh token to exchange for a new access token, the auth server would issue a new refresh token and invalid the previous one. Refer
OAuth Refresh Token Best Practice
But from the OAuth website
https://www.oauth.com/oauth2-servers/access-tokens/refreshing-access-tokens/
It says the auth server can "optionally issue a new fresh token in response, or if we don't include a new refresh token, the client assumes the current refresh token will continue to be valid"
So, it looks like both options (keep or renew refresh token) are acceptable to OAuth2 standard.
My questions are:
1) Do both options are equally secure?
2) If the auth server returns a new refresh token but the client fails to receive (e.g. network error), the client has no way to re-gain access token with existing refresh token, which already invalidated. Correct?
3) If the refresh token has been leaked to someone else, both the attacker and the victim client can use it. If the auth server takes the renewal approach, then only the first one to use the refresh token can re-gain access token. So, if the victim found the refresh token is no longer valid, it may think that the refresh token has been compromised. Is this the reason for the "renewal approach"?
2.) Yes, that's correct.
3.) That's correct too. You can take a look at the OAuth 2.0 for Browser-Based Apps RFC which discusses the refresh token regeneration. It's important mainly for public clients - the ones without client_secret, since a refresh token can be exchanged for an access token right away.
1.) Refresh token regeneration is a security feature - it shortens validity of a stolen refresh token and it enables the auth server to detect that refresh token had been compromised. So it's more secure to use it than not. But it may be more convenient for private clients not to get a new refresh token on each use - for example to prevent the refresh token loss due to network error - as you described it in point #2.

how to get a token in js webapp for bearer-only backend client

I got this setup for my app:
Keycloak server
Keycloak-protected nodejs backend (bearer-only)
PHP/Reactjs frontend
The frontend is optionally login-protected. For some users it will be required to login which will redirect the user to Keycloak server. After a user is logged in, the frontend will have a bearer token to make api calls to the keycloak-protected backend.
My problem is how to get a bearer token for users that don't need to be logged in (anonymous users).
I tried this approach:
Created "confidential" client to be used by PHP.
Frontend PHP gets a bearer token using client_id and client_secret and passes them to javascript (by that I mean, printing out token values inside tag which is a global variable)
Initially, the frontend makes successful api calls because the access_token passed by php is fresh/valid.
After the access_token is expired, I will need to fetch a new one using refresh_token.
But, for that I need client_secret which is not available in the js app (and it's not recommended to save client_secret and password in js app, as you know).
I'm stuck here. I researched, read a lot of documentation, but failed to find a way to achieve that.
One other idea that crossed my mind was to make the bearer access_token long-lived (1 hour, for instance). But, some users may use the app for more than an hour.
At this point, I'm not sure, if it's possible to make anonymous calls to keycloak protected backend from javascript web app.
Is it wrong to have very long lived (for example, 6 hours) access_tokens? What other options do I have?
I have come across a similar situation. You can use following approach.
Your API is always protected by access tokens
Initially, your PHP backend retrieve an access token using Client Credentials Grant
Once UI is loaded, you make a JS call to PHP backend and obtain the correlated access token. You store it to local-storage
This call is protected by session. Initially it's unauthenticated/anonymous access
In case you need access tokens with different scopes (scopes only granted for logged in users, non anonymous case), then you make your end user follow a log in process to obtain new tokens
Once tokens are received, you again store them against the session you have with backend and front-end
UI can obtain the access token to front end through the same backend call
This way you does not hard code access token values to your UI code. Also, backend calls are protected by session.
Additionally,
Refresh token is stored in backend. So it is safe to store and refresh
Client credentials are never exposed to front end
Only burden is the session maintenance with backend. But there are many best practices that are built around this .!
Without adding a lot of complexity, When the access token has expired (user unauthorized request), redirect the user to log back in. This is much much easier because it is the same flow for many scenarios.
The other option is to use something like a session to handle this, which REALLY increases the complexity. https://openid.net/specs/openid-connect-session-1_0.html

Oauth 2: why refresh tokens must be stateful?

I'm working on a SPA app based on Node, with token-based authentication using JWT. Right now, the jwt token never expires, which is not good.
I want it to expire for more security, but I don't want my users to be forced to re-log. That's why I need a refresh token.
So i'm reading about OAuth2.
I have a hard-time to understand why refresh-tokens must be stored in a database, whereas access-token are generated on the fly using a secret key.
Why refresh tokens can't be generated the same way as access tokens ?
Thank you guys !
Refresh tokens usually are generated the same way as access tokens.
An authorization server will often return a refresh and access token if requested (and you're not using the implicit grant type).
The difference is how they are used.
An access-token is usually a bearer token: whoever has it can use it against the resource server, but it is only valid for a short period of time. In which case, storing them in a database is often pointless as they are worthless once expired.
A refresh token however is like having access to a "forge" which allows you to mint a new token.
If you present the refresh token to the authorisation server (not the resource server) you will get back a new access token and possibly a new refresh token.
Providing of course that the user has not revoked/changed access permissions to your application and that the user is still a valid user.
So you would keep them in a database perhaps because your user logs in infrequently. So you may need the refresh token weeks after you got it.
Alternative to the refresh token.
If you are using the implicit grant (which is common with SPAs but not recommended). You can try and keep your end user logged in to the identity provider used by the authorisation server. This way you can keep requesting new access tokens from the auth server without the user being prompted by the auth server for credentials as a session will be persisted between the identity provider and the user's browser.

Resources