Cognito get new token after updating user attributes - amazon-web-services

I have a question regarding Amazon Cognito.
What I want to achieve is to set default custom attribute for the user record.
Ideally it will be great if I could set it by default in user pool, for example "custom:domain": "some name". But I can't find an example for this, or maybe set it up in Pre sign-up trigger with Lambda, but I didn't find examples for it also. What I did, when user authenticate I get the user attributes and set the required one with updateAttributes (I use amazon-cognito-identity-js). The downside of this approach that I faced, on first user login he gets the tokens first and only after that this custom attribute it set. So in first login this attribute is missed in token. What I want to ask what is the best approach of doing this kind of staff? And if my variant is appropriate, how could I update user token after changing the user attributes, so they appear in that token.

You will get the new attributes in the tokens on token refresh. However, the SDK's do not provide a method to manually refresh the tokens. We will consider this as a feature request for our SDK's.
Tokens are typically valid for an hour and are automatically refreshed by the SDK when they have expired. So your user's would get tokens with new attributes at-least after an hour.

Another option would be to add a Pre token generation trigger that checks to see if the value is set, and if it isn't overrides it. http://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-identity-pools-working-with-aws-lambda-triggers.html#aws-lambda-triggers-pre-token-generation-example-1 It would be set the first time the user gets the token if done this way.

Related

Django Simple JWT logout view [duplicate]

I am using Spring Security OAuth2 and JWT tokens. My question is: How can I revoke a JWT token?
As mentioned here
http://projects.spring.io/spring-security-oauth/docs/oauth2.html, revocation is done by refresh token. But it does not seem to work.
In general the easiest answer would be to say that you cannot revoke a JWT token, but that's simply not true. The honest answer is that the cost of supporting JWT revocation is sufficiently big for not being worth most of the times or plainly reconsider an alternative to JWT.
Having said that, in some scenarios you might need both JWT and immediate token revocation so lets go through what it would take, but first we'll cover some concepts.
JWT (Learn JSON Web Tokens) just specifies a token format, this revocation problem would also apply to any format used in what's usually known as a self-contained or by-value token. I like the latter terminology, because it makes a good contrast with by-reference tokens.
by-value token - associated information, including token lifetime, is contained in the token itself and the information can be verified as originating from a trusted source (digital signatures to the rescue)
by-reference token - associated information is kept on server-side storage that is then obtained using the token value as the key; being server-side storage the associated information is implicitly trusted
Before the JWT Big Bang we already dealt with tokens in our authentication systems; it was common for an application to create a session identifier upon user login that would then be used so that the user did not had to repeat the login process each time. These session identifiers were used as key indexes for server-side storage and if this sounds similar to something you recently read, you're right, this indeed classifies as a by-reference token.
Using the same analogy, understanding revocation for by-reference tokens is trivial; we just delete the server-side storage mapped to that key and the next time the key is provided it will be invalid.
For by-value tokens we just need to implement the opposite. When you request the revocation of the token you store something that allows you to uniquely identify that token so that next time you receive it you can additionally check if it was revoked. If you're already thinking that something like this will not scale, have in mind that you only need to store the data until the time the token would expire and in most cases you could probably just store an hash of the token so it would always be something of a known size.
As a last note and to center this on OAuth 2.0, the revocation of by-value access tokens is currently not standardized. Nonetheless, the OAuth 2.0 Token revocation specifically states that it can still be achieved as long as both the authorization server and resource server agree to a custom way of handling this:
In the former case (self-contained tokens), some (currently non-standardized) backend interaction between the authorization server and the resource server may be used when immediate access token revocation is desired.
If you control both the authorization server and resource server this is very easy to achieve. On the other hand if you delegate the authorization server role to a cloud provider like Auth0 or a third-party component like Spring OAuth 2.0 you most likely need to approach things differently as you'll probably only get what's already standardized.
An interesting reference
This article explain a another way to do that: Blacklist JWT
It contains some interesting pratices and pattern followed by RFC7523
The JWT cann't be revoked.
But here is the a alternative solution called as JWT old for new exchange schema.
Because we can’t invalidate the issued token before expire time, we always use short-time token, such as 30 minute.
When the token expired, we use the old token exchange a new token. The critical point is one old token can exchange one new token only.
In center auth server, we maintain a table like this:
table auth_tokens(
user_id,
jwt_hash,
expire
)
user_id contained in JWT string.
jwt_hash is a hash value of whole JWT string,Such as SHA256.
expire field is optional.
The following is work flow:
User request the login API with username and password, the auth server issue one token, and register the token ( add one row in the table. )
When the token expired, user request the exchange API with the old token. Firstly the auth server validate the old token as normal except expire checking, then create the token hash value, then lookup above table by user id:
If found record and user_id and jwt_hash is match, then issue new token and update the table.
If found record, but user_id and jwt_hash is not match , it means someone has use the token exchanged new token before. The token be hacked, delete records by user_id and response with alert information.
if not found record, user need login again or only input password.
when use changed the password or login out, delete record by user id.
To use token continuously ,both legal user and hacker need exchange new token continuously, but only one can succeed, when one fails, both need to login again at next exchange time.
So if hacker got the token, it can be used for a short time, but can't exchange for a new one if a legal user exchanged new one next time, because the token validity period is short. It is more secure this way.
If there is no hacker, normal user also need exchange new token periodically ,such as every 30 minutes, this is just like login automatically. The extra load is not high and we can adjust expire time for our application.
source: http://www.jianshu.com/p/b11accc40ba7
This doesn't exactly answer you question in regards to the Spring framework, but here's an article that talks about why if you need the ability to revoke JWT's, you might not want to go with JWT's in the first place, and instead use regular, opaque Bearer tokens.
https://www.dinochiesa.net/?p=1388
One way to revoke a JWT is by leveraging a distributed event system that notifies services when refresh tokens have been revoked. The identity provider broadcasts an event when a refresh token is revoked and other backends/services listen for the event. When an event is received the backends/services update a local cache that maintains a set of users whose refresh tokens have been revoked.
This cache is then checked whenever a JWT is verified to determine if the JWT should be revoked or not. This is all based on the duration of JWTs and expiration instant of individual JWTs.
This article, Revoking JWTs, illustrates this concept and has a sample app on Github.
For Googlers:
If you implement pure stateless authentication there is no way to revoke the token as the token itself is the sole source of truth
If you save a list of revoked token IDs on the server and check every request against the list, then it is essentially a variant of stateful authentication
OAuth2 providers like Cognito provides a way to "sign out" a user, however, it only really revokes refresh token, which is usually long-lived and could be used multiple times to generate new access tokens thus has to be revoked; the existing access tokens are still valid until they expire
What about storing the JWT token and referencing it to the user in the database? By extending the Guards/Security Systems in your backend application with an additional DB join after performing the JWT comparison, you would be able to practically 'revoke' it by removing or soft-deleting it from the DB.
In general, the answer about tokens by reference vs. tokens by value has nailed it. For those that stumble upon this space in future.
How to implement revocation on RS side:
TL;DR:
Take a cache or db that is visible to all your backend service instances that are verifying tokens. When a new token arrives for revocation, if it's a valid one, (i.e. verifies against your jwt verification algo), take the exp and jti claims, and save jti to cache until exp is reached. Then expire jti in cache once unixNow becomes > exp.
Then on authorization on other endpoints, you check everytime if a given jti is matching something in this cache, and if yes, you error with 403 saying token revoked. Once it expires, regular Token Expired error kicks in from your verification algo.
P.S. By saving only jti in cache, you make this data useless to anyone since it's just a unique token identifier.
The best solution for JWT revocation, is short exp window, refresh and keeping issued JWT tokens in a shared nearline cache. With Redis for example, this is particularly easy as you can set the cache key as the token itself (or a hash of the token), and specify expiry so that the tokens get automatically evicted.
I found one way of resolving the issue, How to expire already generated existing JWT token using Java?
In this case, we need to use any DB or in-memory where,
Step 1: As soon as the token is generated for the first time for a user, store it in a db with the token and it's "issuedAt()" time.
I stored it in DB in this JSON format,
Ex: {"username" : "username",
"token" : "token",
"issuedAt" : "issuedAt" }
Step 2: Once you get a web service request for the same user with a token to validate, fetch "issuedAt()" timestamp from the token and compare it with stored(DB/in-memory) issued timestamp.
Step 3: If stored issued timestamp is new (using after()/before() method) then return that the token is invalid (in this case we are not actually expiring the token but we are stop giving access on that token).
This is how I resolved the issue.

stateless authentication and permissions in the JWT token

Users in the applications have permissions based on the groups they are in
We would like to store the list of groups a user is in, in the JWT token
When a user gets added or removed from the groups, that effectively means the permissions change and this is what should happen at the user's end:
If they have been removed entirely from the system, the user immediately is kicked back out to the login screen
If they have just been removed from a group, for example, the user is not kicked out
They are notified that their rights have been updated, they are told to please refresh the page
when the user refreshes, they stay on the page they are looking at
If the user is on a screen they no longer have access to, they are sent to the home page
1. We have so far been writing REST APIs that are all stateless but this seems to break that. What is the best way to achieve it?
2. If we were to keep it simple and ensure statelessness, What's the best approach?
With stateless authentication your ID token which contains your group information, isn't renewed until it expires (usually an hour). You can reduce this duration to 5 minutes. This would be the simplest way to make sure any update to group is reflected on the front end quickly. These tokens are independent and cannot be revoked once they are issued. Even if you run the global sign out API call or the forget device API call, only the refresh token is revoked, while the ID and access tokens are still valid until they expire.
The requirements you mention aren't compatible with a stateless authentication method. Sure, you can create a "hacky" flow where you have a database that records the id of users who are kicked out and before every call it checks the database but it would be a lot of unnecessary work and you would be defeating the whole point of using stateless authentication.
My suggestion, if you want to keep using cognito, is to reduce the expiration time of all tokens to the minumum. You can also eliminate refresh tokens from your flow but that would mean user needs to sign in every 5 minutes.
But if you really need to implement this, I would suggest using stateful authentication methods.

Get user from refresh token in Django Simple JWT's TokenRefreshView

I am trying to check if the user still exists when Refreshing the Token, returning the user's updated detail (if updated) upon refreshing a token. Is there anyway to retrieve the user's details from the refresh token? [request.user] is currently marked as AnonymousUser so I am unable to know who the refresh token belongs to.
I think it is a good practice to have one endpoint to one type of job. In your case, it will be good to have:
endpoint for a token refresh,
endpoint to get user details.
Please take a look at Djoser package. It has predefined views and URLs that you can reuse.
If you really want to get some user info on refresh, then you can try to put some user's information in jwt payload part. But I would rather go with to separate endpoints. If user will not exists, then refreshing the token won't return new token.

Is there a way that we can avoid multiple token generations for a single user if he/she try to login on different browsers?

I am using django-rest-framework-jwt in my backend and calling API's from Angular Project.
When user try to login on multiple Browsers, each time a new token is generated for the user on new browser. And every token is valid.
What I want is that when user is already logged in in one browser and he/she tries to login on second different browser the previous token for first browser should be invalidated.
In a simple word, NO, you can't just avoid generating tokens unless you made a little twist in django-rest-framework-jwt module. But that's not pure jwt anymore.
JWT stands for JSON Web Tokens and it's a mechanism for exchanging data between computer systems that happens to be convenient for generating authorization headers that can be used to implement statless auth in web apps.
SO
stateless means that you don't track user tokens, You just verify them. If token is valid and the payload is valid, then OK. It doesn't care how many tokens are generated and it doesn't care that they are related to one user. The token is created based on timestamp and will be verified compared to lifetime and timestamp of it.
It means that django rest jwt module, will create a token based on current timestamp of system, whenever user request for it.
Remember you can't delete a jwt token. Because it's not stored in database. So if your token is spoofed, that's it. You can't do anything with it, unless life cycle of the token ends and token expire.
If you want to track these tokens and be able to control them and for example don't create redundant tokens for a user as you asked:
consider changing to another token based authentication that stores token in database so you could track it.
change jwt system to what is suitable for you (I did it before). For example add a lookup id in database and check tokens by that bounded to each user. I know it's not jwt anymore, But you can still use some goodies of it. Like don't hit database on not valid jwt tokens and store some payload in it, if verified don't hit database for that info. Like permissions and ...

AWS Cognito: update JWT ID token on user's attribute change

I want to add to the token's payload a specific attribute. This attribute can be changed rarely (once per month), however I would like that the tokens would be updated immediately after this change.
WORKFLOW
In web/mobile app, user opens a profile view and changes attribute X. The current value of this attribute is also stored in ID token. So when user submit edits, the new value of X should be saved on the backend and should replace the old value in ID token. It is important, because attribute X determines whether user can or cannot do specific things in app.
What does Cognito do when payload's attribute change? It sends new version of JWT ID token in the next request?
Should I use refresh token? Or force to sign-out and sign-in user?
Refresh token will be more appropriate in this usecase. Currently, refresh token flow is not exposed in the high level android SDK for user pools because it is done behind the scene by the SDK. For now, you might have to call the refresh token from low level SDK to get around this.
(I am a developer from Amazon Cognito team, we will take this as a feature request to allow this from our high level SDKs.)