AWS Cognito - How to keep idToken alive forever? - authentication

When the user gets authenticated, AWS Cognito provides three tokens - idToken, accessToken, and refreshToken.
AWS Cognito configurations only allow a maximum of 24 hours expiry time for idToken, see below image.
Now if we look at apps like Facebook, they never expire user login automatically. But in our case, the user needs to log in every 24 hours once.
Question: How can we keep idToken alive forever using refreshToken or something else? Please also guide me in case I need to do it on the server-side, what best I can do to ensure all idTokens are refreshed in a timely manner.

You cannot keep an ID token forever. As you noticed yourself, the maximum validity time for an ID token is 24 hours. There is literally nothing you could do to change this configuration.
There might be a way around it, but you need to keep refreshing the ID token using the refresh token. The refresh token can be configured to expire after 10 years. All you have to do is to keep on using it every time you see that the ID token expired. If you are using an SDK it will normally do it for you. You just sing in once and the SDK will keep on refreshing the ID token.
Just keep in mind that you will get a new ID token (as well as an access token) each time you use the refresh token. It does not update the validity of the original token.

Related

If you implement refresh token rotation, isn't better to keep track of current user token than blacklisting used ones?

I don't see a point in which you would with implemented refresh token rotation blacklisted tokens instead of keeping track of current ones.
If you are blacklisting tokens, you would get a lot of tokens blacklisted very fast. Let's assume your access token TTL is 5 minutes and your refresh is 7 days. If user is using your app for and hour, he would blacklist 12 tokens in that time. If you have great number of users, that would be a lot of blacklisted tokens.
Problem with that is also theft of refresh token. If someone managed to steal it, they can immediately exchange it for pair of new tokens, users active token (that is stolen) would be blacklisted and thief could just use your app normally from that point. How to solve that? Your user would provide blacklisted token on next request and would be logged out, he will log in again and start normally using app but so does the thief, since his token is valid, unless you invalidate his token somehow, but for that you need to keep track of current tokens.
Why just don't keep track of current client token? On every refresh request, you just check if provided token is current users token, if it is not put token value in database to "null". That why users will be forced to log in even if they stole your refresh token since current token must be valid to even check the database if it is same as current (because if refresh token is invalid or expired, you must logout user). Next time they log in, you would set new current refresh token in database and thief can't do nothing with stolen token.
Isn't this breaking stateless rule? It does, but in classic session you need to check database on every request, in this system you would check only when access token expires.
Plus, you don't need to keep track of possible of millions blacklisted tokens and you prevent from refresh token theft.
Only downside I see is that if someone actually steals your refresh token, and you never make any requests after that, they will be logged in until they log out or somebody sends bad request to refresh token endpoint that will "lock" your account.

Revoking JWT with No Expiration

I'm looking to employ token-based authentication for a mobile app that keeps the user logged in as long as they have not logged out. My approach is to create a JWT refresh token when the user logs in/signs up; This token never expires, and continues to refresh 20 minute access tokens.
The problem arises when they log out. I've read the best way to go about this is to blacklist the JWT on Redis to store revoked keys. However, since the JWT never expires, the record can never be removed from Redis and can start to chunk a lot of my memory.
Should I be worried about this, or is Redis memory-efficient on this respect? Is there a better way to revoke JWT with no expiration?
A JWT token is a self contained token. That means that it lives on its own until it expires and can't be revoked. So by definition it must expire. Because when it falls into the wrong hands, it'll give access to your resources without being able to revoke it. So yes, you should be worried with this implementation.
The problem here is that you trust the refresh token itself, because it's a JWT. You should in fact trust the server. Not because the JWT can't be trusted, but because the refresh token doesn't have to be a JWT.
Save refresh tokens in memory including the expiration time. You can remove expired tokens from memory. This means that only tokens that exist in memory can be used to request a new access token. And to be on the safe side, use one-time only refresh tokens.
The flow would be something like this:
the user logs in, receives a JWT access token (5 minutes) and the refresh token 1 code (48 hours). Refresh token 1 is saved on the server.
five minutes later: the access token expires
a new access token is requested using refresh token 1.
user receives a new access token (5 minutes) AND the refresh token 2 code (48 hours). Token 1 is removed from memory and token 2 is added to memory.
and this goes on for several hours.
For two days the user doesn't use the app
50 hours later: because both tokens are expired, the user has to login again. Resetting the flow.
On logout remove the refresh token from memory. And if in the meantime you wish to revoke access. Simply remove the refresh token from memory. Within 5 minutes the user has to login again.
JWT also needs to be revoked as best practice.
Yes, JWTs are self tokens and expirations already part of themselves.
But if user logs out and still their JWTs are not expired means someone can use that token to call different APIs. So it is a security breach.
To avoid such things we should maintain JTI claim of that JWT in our backend with the same TTL with the value of JWT "exp".
When the user logs out we have to clear those JTIs and notifcy the API callers about this just putting into some event service from their API Gateways should get to be notified and clear their side cached tokens if anything and cross check with identity system (Introspection).
This is we have to design the system to avoid further security related issues.

How to Oauth Get Access Token with No Expiry in Google Dialogue flow API

Normally Google Access token is valid for one hour but I want to set it to no expiry. How can I do that, please help
Google access tokens are only good for one hour this is Oauth2 standard and can not be changed. You will need to use a refresh token to request a new access token. No idea if that is possible with dialogflow you will likely have to request your user authenticate again after an hour.
OT: Thats an impressive app you are working on if your users will be using it beyond the access token limit.
According to [1], OAuth token maximum lifetime is 1 hour (3600 seconds) and it cannot be changed.
If your intention is that your application may continue working without having to "manually" recreate a new token, then you could try creating a session client that scopes to multiple requests, as described in the Best Practices Dialogflow reference [2]:
"To improve performance, you can use a single instance of a session client object for multiple requests. The session client reuses the same access token for as long as it is valid (typically one hour). Once it expires, the session client refreshes the access token automatically, so you don't need to recreate the session client to refresh your access token. Your request that also refreshes the access token can take an extra second or two".
Please, try this and let me know the results.
[1] https://cloud.google.com/iam/docs/creating-short-lived-service-account-credentials#sa-credentials-oauth
[2] https://cloud.google.com/dialogflow-enterprise/docs/best-practices

JWT token refresh (sliding sessions) and signout

I am very new to JWT and I ended up inheriting a codebase which makes use of JWT. Now there are some very fundamental problems which I am facing and I am not finding any answers. This question is not code based so please bear with me.
Let us say that my JWT token is valid for 4 hours. Here are my requirements/constraints
If a user is working at 3 hours 59 minutes. their session should get extended by 2 hours and they should not be required to re-enter credentials.
The client side java script must not cache the user credentials in any way.
It is OK to refresh the JWT token with a new one... but you must not do it on every request you make on the server. So the client has to be intelligent to refresh the JWT token when the time is right. You must not try to issue a new token on each and every request you make to the app, because we will end up in a scenario where we have 1000s of active tokens generated within the course of a session and all of them are active. this makes the signout requirement even harder.
Once a user clicks signout. the JWT token should not be usable anymore. Even though its life time is still valid.
If a signout occurs. All tokens which were issued (as part of session extension) should get invalidated. Not just the last one.
I am starting to read about JWT but it seems like my requirements cannot be met with JWT. these requirements are very easy to meet with the session id approach. but I don't want to give up on JWT just yet.
JWT life extension
You can issue a JWT with the old one. Your client app have to request a new JWT when it is close to expiration time. Client knows the expiration time reading the exp claim and can invoke a refresh service to get a new token. If the client app is closed then the JWT will expire and it will be necessary for the user to present the credentials again
Logout
It is recommended to let tokens expire, but you can use a blacklist to store JWT that are still valid but can not be used for authentication:
When user clicks logout
After refreshing a ticket close to expiration time
You will need to add to JWT an unique identifier jti. The blacklist will contain jti and exp. Once current time > exp the entry can be discarded.
See Invalidating client side JWT session

Time expiration issue in JWT

As you know, there are some good reasons for using token based authentication instead of session based.
In session based, of course there is a expiration time. So if user is not active for a while, his session get expired. But before expiring, if he send request to server, his time will be extended.
There is an awesome tutorial here about JWT. I have a question about expiration time for token. Imagine we set the expiration time to 100 seconds, then we sign the token. It doesn't matter user is active or not. After 100 seconds that token will not be valid anymore. This bothers the user. Is there any way to extend the time?
Is it a true approach, or maybe I have a mistake. Any idea?
If I understand the question correctly, it is fairly simple to alter the expiration of a JWT token during creation...
The "exp" (expiration time) claim identifies the expiration time on
or after which the JWT MUST NOT be accepted for processing. The
processing of the "exp" claim requires that the current date/time
MUST be before the expiration date/time listed in the "exp" claim.
More information can be found here https://www.rfc-editor.org/rfc/rfc7519#section-4.1.4
Basically the exp key takes a unix timestamp - set the timestamp to > 100 seconds from now and you will accomplish your goal.
To "refresh" the token your API needs a service that receives a valid, JWT and returns the same signed JWT with the updated expiration.
Silent refresh
There are 2 major problems that users of our JWT based app will still face:
Given our short expiry times on the JWTs, the user will be logged out every 15 minutes. This would be a fairly terrible experience. Ideally, we'd probably want our user to be logged in for a long time.
If a user closes their app and opens it again, they'll need to login again. Their session is not persisted because we're not saving the JWT token on the client anywhere.
To solve this problem, most JWT providers, provide a refresh token. A refresh token has 2 properties:
It can be used to make an API call (say, /refresh_token) to fetch a new JWT token before the previous JWT expires.
It can be safely persisted across sessions on the client!
Here a brilliant exhibition in HASURA BLOG--> https://hasura.io/blog/best-practices-of-using-jwt-with-graphql/
You didn't give further information, but I'll assume you are going to use JWT for web-browser authentication.
you can save your JWT in a cookie with httpOnly and secure attribute and set cookie expiration time long enough(maybe 1 years) and inside of your JWT claims set exp property to a shorter time ( maybe 1 week or something else). now in every request the cookie will be sent to the server so you can check for expiration time.
something like this :
if(decodedJwt.exp < Date.now()){
//token is valid, do your stuff
}else {
//token expired, regenerate it and set it to the cookie
//also update the expire time of the cookie
}