Is Refresh Token relevant for OIDC IdentityServer Azure AD SSO Implementation? - azure-active-directory

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.

Related

The gmail api refresh token does not work

I am using the Gmail api to send e-mails from my Oracle database.
After a while, the Oauth2 token expires and the token needs to be refreshed with, using the refresh token.
All of this works fine (in both Postman and Oracle).
When the mail has not been used for a while ( a few weeks) the refresh token doesn't work anymore.
Then I need to get a new authorization code etc. It seems as if the gmail-api revokes its grant after a certain time.
Is there a way to work around this ?
thanks in advance.
Servé
There are a number of things which can cause a refresh token to expire here are my top three.
Applications that are still in testing, and have not bee though the google verification process will have their refresh tokens expired within in two weeks.
If the user changes their password this will also cause a refresh token to expire when using the gmail scopes.
If you authorize the app, then authorize it again you get two refresh tokens both will work, you can have up to fifty outstanding refresh tokens once you have hit that number the first one will be expired, as you can maximum have fifty outstanding refresh tokens.
Have a look at the possible refresh token expiration reasons here: https://developers.google.com/identity/protocols/oauth2#expiration

How jwt token get reissued in azure ad OuthImplicitFlow

Currently the scenario is. When I am trying to access my app,it first sends my app to Microsoft login page and after successful login it returns a id token which is used to retrieve the data from backend server. Now the expiry time of token is approx 1 hr. Now when this token expires, Microsoft issues a new token(JWT Token), it not redirects me back to login page.
But ideally it should be redirected to login page, as in implicit flow, there is no refresh token. Then on what basis it is issuing a new token ?
I am using Microsoft adal library in my front end side for authentication.
here's the link: https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-implicit-grant-flow#refreshing-tokens
The implicit grant does not provide refresh tokens. Both id_tokens and
access_tokens will expire after a short period of time, so your app
must be prepared to refresh these tokens periodically. To refresh
either type of token, you can perform the same hidden iframe request
from above using the prompt=none parameter to control the identity
platform's behavior. If you want to receive a new id_token, be sure to
use id_token in the response_type and scope=openid, as well as a nonce
parameter.

Google OAuth2 flow and id_token refresh

I am having troubles in implementing OAuth in the right way.
I use a client/API architecture (Angular for front and Node.js for back) and I would like user to sign in using Google OAuth authentication only.
Here is what I think is the right way for the moment (tell me if I misunderstood something) :
Angular open a Google popup asking user's consent.
Once the user agree, Google Authorization server sends back to angular a verification code.
This verification code is forwarded to an API endpoint.
Then, the API asks Google Authorization server to exchange this code for an access_token, an id_token and a refresh_token.
Google sends those 3 tokens.
The API uses access_token to retrieve user from Google API
The API persists the user
Here is the little dillema, in my opinion, the access_token and refresh_token should be stored into the database and the id_token should be sent back to Angular client.
This way, it would allow the API to ask for resource in Google API and if the token expires it can still ask for a new token thanks to the refresh_token.
Client-side, the id_token is embedded in all requests thus allowing the API to identify the client and verify his authentication with Google certs from https://www.googleapis.com/oauth2/v3/certs.
Supposing this is right way to use tokens, how could I deal with id_token expiration since client does not have any refresh token ?
Thanks !
I do it slightly different (I have the same basic architecture though).
Angular decides the user needs to log in and displays a login popup.
The url in the login popup is not serviced by angular, but is instead directly run off of the backend server: /auth/google . (I use hapijs and bell, personally).
/auth/google is serviced by a bell plugin and initiates the OAUTH dance.
the end of the OAUTH dance results in my node server generating a local token (I just generate random bytes and store them in redis mapped to user ids)
because the initial login popup was created by window.open, the success page (generated on the api side rather than in angular) can use window.opener.postMessage to communicate the token back to the angular runtime.
This way, all my sensitive google credentials (the user's oauth token, refresh token if needed, and my application's api ID and secret) are only on the server, except for during the OAUTH dance relay when they're in a URL string during the client redirects. This is reasonably secure.
Then for all the actual user interactions with the api, I use the token I generated in step four to authenticate. This could be a JWT if you wanted, but I don't do it that way; I just use redis to map from 'longrandostring' -> userId. That lets me (for example) force everyone to re-login if I wipe the redis database that has all the tokens stored, or I can write a lua script to delete all the entries that map to a certain userid.
If you need a refresh token, you can set access_type=offline in the initial request to oauth2/auth, and you'll get a refresh token as part of the response, unless you've previously gotten a refresh token. You can then persist it on the server side and get new access tokens as needed. If you set approval_prompt=force as well, you'll force a new consent screen and be guaranteed a refresh token (but after some small number of refresh tokens granted to a user, older ones expire on the same application so it's best to only request them if really needed).

What is the correct way to implement a stateless authentication?

I am new to the Single Page Application. One big question for me is how to make my application secured. I am using React in the front-end and express + mongodb in the back-end.
I old web site, we use session to do the authorization. If session is timeout, we can let the user redirect to the login page. And if a user is keep do some actions on our website, his session will never expired.
But now, I am using JWT to do the authorization. A token may expired in 1 minuet, after that, the user have to login again.
For my understanding, one way is 're-send a token on every request/response, then each request/response will have a new token'. But I think this is not the correct way of how to use JWT.
So my questions are:
What is the correct way to avoid the user login again if he still work on our web app?
Do we need to store the token in the database (mongodb)?
If I store the token in localStorage, everyone can borrow it from the browser and copy the token into their client. How to avoid it?

when using mirror api, how do i handle access token expiration

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.

Resources