const router = express.Router();
router.post('/refresh', ...{})
The access token expiration period is 7 days and the refresh token expiration period is 30 days. If 7 days have elapsed, it notifies the mobile app client that it has passed, and the client sends a refresh token to the server to check if the refresh token is valid, and immediately receives a new access token for 7 days and a refresh token for 30 days. It's all right here, right?
But what about after 30 days?? What if the user doesn't log in for 30 days? The refresh token will also expire. And I want to keep sign in forever. (This is the for mobile app, so re sign in is not good for user experience) I don't know what to do at this time.
You have a few options depending on the intended functionality and security requirements of your application.
Change expiry period of one or both tokens, possibly make refresh token infinite to maintain some security
Is background refresh an option you can consider? If this can be completed without the user having opened the app it will work well for you.
Store user credentials and re-login (either automatically or manually) if re-accessing after the refresh token has expired.
Related
I have a multitenant web api project with microsoft azure integration. I connect to microsoft, get access token and refresh token and each time before access token expiration, I call api
POST https://login.microsoftonline.com/tenant/oauth2/v2.0/token
data in request is:
grant_type=refresh_token
refresh_token=xxxxxxxxxxx
client_id=xxxxxxxxxx
I get new access token and refresh token, and after an hour get new access token with the same api and last recieved refresh token. But after 24 hours somehow my refresh token expires, and I need to reconnect and enter my credentials again.
How to make my refresh token don't expire until i revoke it manually. I need somehow update refresh token timeout in background and save my integration always connected until i revoke it manually.
I need somehow organize this to stay connected always until manual revocation. Any solution?
There is a 24 hour limit to refresh tokens under certain conditions:
Refresh tokens sent to a redirect URI registered as spa expire after
24 hours. Additional refresh tokens acquired using the initial refresh
token carry over that expiration time, so apps must be prepared to
rerun the authorization code flow using an interactive authentication
to get a new refresh token every 24 hours. Users don't have to enter
their credentials and usually don't even see any related user
experience, just a reload of your application. The browser must visit
the log-in page in a top-level frame to show the login session. This
is due to privacy features in browsers that block third party cookies.
See: https://learn.microsoft.com/en-us/azure/active-directory/develop/refresh-tokens
In doc https://learn.microsoft.com/en-us/azure/active-directory/active-directory-configurable-token-lifetimes, it said:
Confidential clients are applications that can securely store a client
password (secret). They can prove that requests are coming from the
secured client application and not from a malicious actor. For
example, a web app is a confidential client because it can store a
client secret on the web server. It is not exposed. Because these
flows are more secure, the default lifetimes of refresh tokens issued
to these flows is until-revoked, cannot be changed by using policy,
and will not be revoked on voluntary password resets.
Now for my webAPI app, I should make sure refresh token neve expire.
My questions:
1.Does refresh token for Confidential clients neve expire until revoked?
2.When I use old refresh token to get new access token, server will return a new refresh token which is difference from old refresh token. Should I use new refresh token to replace old refresh token? Or is that both old and new refresh tokne will neve expire unitl revoke?
One critical piece of text in that documentation:
will not be revoked on voluntary password resets
So it means for confidential clients, refresh tokens are not revoked if the user changes their password.
However, I do not believe this applies to a reset done by an admin.
Whenever you use refresh tokens, you must be prepared for the case when the token does not work.
If your app has critical features depending on that access and cannot handle downtime for access to the data, you need to use application permissions.
There is this bit for the second question:
Refresh Token Max Inactive Time (issued for confidential clients) 90 days
So a refresh token which is not used for 90 days will no longer work.
I would replace the current refresh token with the new one always, and make sure to refresh the refresh tokens periodically if it is possible they don't get used.
When logging in, a JWT access token is sent from the server and saved in AsyncStorage in RN.
Now I want the user to stay logged for 5 years, until they either:
log out
admin revokes their token
they are logged in on 3 devices, change their password on one of the devices, which should log them out from the other 2 devices until they login again on those devices
lose their phone, and login from another device to log out from all devices
It looks like I'd have to store JWT tokens in the DB (I know that's not the point of JWT tokens and defeats the purpose they are serving based on my reading) but I would need to know the user's tokens, on their different devices, to be able to revoke them.
One thing that confuses me is reading that the access tokens should be short lived, say 60 mins, and refresh tokens long lived, say 5 years in my case.
What I don't understand is why can't we just use the access tokens to have a 5 year life span (for each device), save them against the user in the DB so we can identify their tokens and revoke their tokens based on the aforementioned points? What would be the point of a refresh token, would it even be needed in this case?
Note: I also read that we can't revoke access tokens, but can only revoke refresh tokens, so I am really confused. Would I have to send both an access token and a refresh token to RN, and only use the refresh token for the Authorization Bearer header and save only the refresh token in the DB? Then what would be the point of the access token if it's not the one in the DB?
I think this should be something simple to implement, but my criteria are the 5 year login and being able to revoke tokens based on the points above.
What's a correct solution for this situation?
Access Tokens are short lived, which is by default 24 hours. But why? Why not 5 years?
Anyone with the access token is guaranteed access to whatever the user (to whom it was originally issued) can access. This means the server cannot differentiate between that user and anyone else who has the access token.
There is NO logging out. What I mean here is that you can have your front-end redirect to sign-in page to have him enter the credentials, but truly logging out does not happen in the server. Technically, the user can use the same access token to continue getting access (until it expires)
Access Tokens canNOT be revoked. Access tokens are invalidated only upon expiry. Anyone can use it until the token expires. For instance, if the expiry is set to 5 years and I happen to get your token by some chance, I can have all access that you have till it expires which in this case would be 5 years. This is exactly what gives more sense to set the expiry time lesser than 24 hours.
Now lets address your queries. "I want to user to be signed in until he"
Logs out
Send refresh token to user after he signs in. Store both access token and refresh token very securely. After his access token has expired, use the refresh token to get a fresh access token. Loop this until he logs out. When he logs out, delete the access token and refresh token on the front-end and revoke the refresh token on the server side. (Again, if he somehow gets the access token, he still can access his account till it expires)
Admin revokes token
The server can't revoke access tokens as I told before, once issued its valid until expiry, no matter what -> But only as long as the user has the access token :P Delete the access token as soon as he opens the app, if he did not last open the app in the past 1 hour or so. Now the front-end is forced to get a new access token using the refresh token it has stored. Now, you want the user to force logout? Revoke his refresh token.
Logout on all devices after password change
Same as 2. After he changes password, revoke all refresh tokens issued (In case you don't want the user to sign in again, revoke all refresh tokens except for the current device). Your app on all devices will be forced to get a new access token using the refresh token, but since you revoked it, the user has no way other than to log in using his credentials.
User-triggered logout from all devices
Same as 3. Changing the password triggers logout on all devices and here you just need to add a "Logout on all devices" button that will send a server request which revokes all refresh tokens except for the current device.
Caveat: Current user session cannot be closed; You need to wait for the user the exit the app, so as to have the current access token deleted. Workaround is to delete the access token as immediately as he closes the app (or even he minimizes the app) or setting the access token expiration to 30 minutes, provided you can tolerate the latency caused by obtaining new access token using the refresh token everytime he does that. You need to tradeoff time for security or vice-versa, depending on the your app specifications.
"That's all fine, but I don't want a refresh token in the first place" (Alternative Solution):
I don't encourage storing tokens as it defeats the very purpose of scaling and preventing easy DDoSes, by increasing the response time which increases due to querying the db. But since Redis is amazingly fast key-value store that runs on memory, some prefer storing access tokens in it. Well how does that work?
Setup: Once the user logs in, issue an access token. store it in Redis, then send it to user.
Check JWT signature && token's integrity, if it fails hurray, no db query. Send back 404 user not found. This will be as quick as how JWTs without Redis function.
If it succeeds, check Redis for the token. IF it exists, grant access. If it doesn't, ask the user to log-in again. Note that this will be a bit slower than granting access using just JWTs, but hey, you aren't storing in it Postgres or Mongo, which might take a few milliseconds to respond; Redis being a key-value store - and for it sits on memory (and not storage) - is considerable faster than those.
Access is granted if and only if both the conditions are satisfied: JWT is valid. JWT is present in Redis
Answering your queries:
Logouts are now possible. When user hits logout, delete from Redis the access token. He can't login even if he has the access token. Access Token is now literally invalid.
Admin forces logout: Delete access tokens for that user from Redis.
After the user is successfully granted access by the server, you shall allow the user to issue a request to delete all other tokens with the same user-id (or uid) which will allow logout
After password change, issue such a request.
On Logout from other devices, issue such a request.
Finally the left out 1. Stay logged in until user logs out: Now that you have authority to invalidate access token which you didn't have when not using Redis, you can have a 5-year valid access token, provided you implement other required security measures to prevent misuse of the access token.
We are using Azure AD authentication with a bootstrap MVC site.
Everything is fine and dandy - except we have an issue with the token timeout.
I have read multiple articles about the token lasting 1 hour before re-authenticating against Microsoft.
Our problem comes up when posting data.
Efter we enter a page with a post form on it - and this hours expires when on the page - the post data gets lost when posting the data. Everything points in the direction of the problem occurring when the site goes to get a fresh 1-hour token.
Has anyone here had experience with this or have any idea of how to get around this problem?
Not sure if this is the right way of doing things, but this is how we're handling this situation.
Basically when a user authenticates against Azure AD, you get 3 things back - Access Token (which expires after 60 minutes), Refresh Token and Token Expiry. What we do in our application is cache these three items.
Whenever we perform something that requires Access Token, we first check if the token has expired or not (by comparing the server date/time with the token expiry). If the token is not expired, we simply use that access token. However if the token is expired, we fetch new tokens using refresh token (fetching new tokens using refresh token will again return Access Token, Refresh Token and Token Expiry which we cache again in our application).
Have been reading on refresh token and could not find on the following. information
When does an refresh token expire?
Can a password change by the main user cause a refresh token to expire?
Can I explicitly set some dates for expiration of refresh token
Thanks
Chris
Have a look of this post.
http://www.cloudidentity.com/blog/2015/03/20/azure-ad-token-lifetime/
Refresh tokens last for 14 days, but If you use a refresh token
within those 14 days, you will receive a new one with a new validity
window shifted forward of another 14 days. You can repeat this trick
for up to 90 days of total validity, then you’ll have to
reauthenticate.
Refresh tokens can be invalidated at ANY time, for reasons
independent from your app (e.g. user changes password). Hence you
should NOT take a dependency on the above in your code – your
logic should always assume that the refresh token can fail at any
time.
Refresh tokens issues for guest MSA accounts last only 12 hours