Best practises using JWT for authentication - authentication

I have read a lot of articles related to JWT (JSON web token) use for authentication and got really confused, since everyone has a different opinion on what is a secure way of using them. By saying secure I mean handling logouts and password changes. Also, what data should not be saved in JWT payload.
My question - Are there any industry standards when using JWT for Auth, if yes what are they? If not, is it secure to save password hash and logout date in JWT to handle logouts and password changes, if not what are the alternatives?

Are there any industry standards when using JWT for auth, if yes what are they?
First of all, access tokens (as any type of sensitive information) must only be sent over a secure connection.
On my understanding, you want the ability to revoke the tokens when some sort of event occurs. In this case, you should consider keeping the track of tokens somewhere in your server.
To achieve it, you could assign a unique identifier to each token and then store such identifier in your server. When validating the token, besides checking the signature and the expiration date, you must also check whether the token identifier is whitelisted.
And, to assign a unique identifier to each token, you can use the jti claim:
4.1.7. "jti" (JWT ID) Claim
The jti (JWT ID) claim provides a unique identifier for the JWT. The identifier value MUST be assigned in a manner that ensures that there is a negligible probability that the same value will be accidentally assigned to a different data object; if the application uses multiple issuers, collisions MUST be prevented among values produced by different issuers as well. The jti claim can be used to prevent the JWT from being replayed. The jti value is a case-sensitive string. Use of this claim is OPTIONAL.
If not, is it secure to save password hash and logout date in JWT to handle logouts and password changes, if not what are the alternatives?
If your JWT is a JWS, you shouldn't put any information that is considered sensitive in the payload.

Related

Why should I store a JWT refresh token server-side?

I've read several articles (such as this and this, and this SO answer) that suggest storing refresh tokens server-side in a database, or in-memory (or an in-memory store, such as Redis). From what I understand this is so they can be revoked.
Is there a good reason for storing all tokens as these articles suggest, rather than just storing blacklisted tokens on logout? If I understand the reasons for storing tokens, surely I could achieve the same effect by storing a token id in Redis (with a TTL as long as the expiry, so that the table doesn't grow unweildy).
Are there downsides to this approach, and if so, what are they (or conversely, what are the upsides of storing all tokens, vs just a list of revoked tokens?)
To elaborate, and why I think it should be fine to have a revocation list, here's the process I am imagining:
Issue tokens out
Once revoked (say, on logout), add an entry to a blacklist for a unique id (say, public_user_id if there are many tokens for different devices) with the revocation time, and add a TTL until the token's expiry
When a token is provided for auth, when there is an existing blacklist entry:
if a valid token is used, it'll be before it's expiry and have a creation time after the blacklist entry creation time for the unique id
if an invalid token is used, it'll either be expired or within the blacklist with the unique identifier before the entry creation
Am I missing something critical in that flow that would require a list of all tokens instead?
The advantage of having a list of all issued tokens is that you can have a full view of who has been already authenticated and has currently access to the system. You can then choose to revoke some tokens from this list based on any criteria (e.g. the age of the token, the roles associated with the user of the token, the IP address ranges).
If you only have a list of revoked tokens, it would be impossible to choose at runtime, an arbitrary criteria, to revoke a subset of the valid tokens. Stated otherwise, if you don't have a list of all issued tokens, the revocation criteria cannot be enforced globally at once, but only when a token is presented to a resource server.
The only deciding factor I can think of, that will require a list of all refresh tokens is the following:
Do you / will you, at any point, need to have a functionality where you can dynamically revoke valid refresh tokens, based on some arbitrary, regulatory, legal, integrity, security etc. criteria?
If so, the least you will need is a list of all issued tokens, plus any metadata required to implement the criteria logic.
Example: "Due to regulation, I need to ban all EU users" equates to delete from refresh_tokens were user_ip in <... eu logic ...>
I would aim for a direction of technical simplicity here, since the Authorization Server (AS) should do the hard work for you. Here are some end to end notes which explain some tricky aspects and suggest a simple direction.
1. TOKEN ISSUING
The user authenticates (and optionally consents) resulting in a token 'grant'. The AS should then store refresh tokens for you, in a database table that might be named 'delegations'. Typically the stored 'token' will be a hash rather than the real value, and will be linked to the application (client_id) and user (subject). Tokens issued might have these lifetimes:
Refresh token: 4 hours
Access token: 30 minutes
2. TOKEN REFRESH
OAuth clients such as mobile apps will silently renew access tokens during the lifetime of the grant or 'user session'. This involves sending a refresh token to the AS and getting back a new access token. For this to work the AS needs to store a hash of the refresh token in order to be able to validate the input.
3. DEFAULT REMOVAL BEHAVIOUR
When a user logs out, tokens are cleared from the client app, so they are gone. Newer OAuth 2.1 recommendations are to use rotating refresh tokens, where each access token refresh also renews the refresh token and invalidates the previous one. In our example this now means that the lifetime of a stolen refresh token is likely to be reduced - perhaps to only 30 minutes.
4. MANUAL REVOCATION BY ADMINISTRATOR
If for some reason you want to explicitly deny access to a particular user and application, an administrator could use the AS database and issue a command like this, though the Admin UI may provide more visual options.
delete from delegations where client_id=[value] and subject=[value]
Whether manual revocation is likely to be manageable at a people level is questionable but it is a good capability to have, eg in security reviews.
5. REVOCATION OF REFRESH TOKENS ON LOGOUT
Of course the client can revoke its own refresh tokens on logout if required, before clearing tokens. This should also ensure that any access tokens for the same grant are rejected by the Authorization Server.
6. ACCESS TOKEN VALIDITY
Access tokens are most commonly JWTs. Revocation or logout may occur when the JWT still has 25 minutes to live. If an attacker has somehow intercepted an access token (which shouldn't usually be possible) they can continue to use it against your APIs - during this period the AS will never see the access token.
7. API GATEWAY SETUPS
In a more sophisticated setup, opaque access tokens are issued to internet clients, then sent to an API gateway, which introspects them, as in the Phantom Token Pattern. The gateway also maintains a cache of the access token result.
At the time of revocation the AS can raise a Custom Event to inform the API Gateway, which can then clear any cached access tokens for the user. This should ensure that the very next request with an access token for the revoked (or logged out) user is rejected.
SUMMARY
Unless you are dealing with a very high security domain I would aim for simplicity and follow these two principles:
Leave token storage and revocation to the Authorization Server
Keep tokens short lived so that revocation becomes less of an issue

What is the standard practice to store JWT tokens in Redis?

Should I store the JWT token as a key and corresponding user info as value in Redis so that I can fetch info by token if valid
or
should I encode the user data in JWT itself and use Redis only for storing valid tokens?
The all idea of JWT is that won't need to access the DB (or Redis) on every call and the user access data will be encoded in the token.
Saying that, the biggest drawback of JWT it that you can't actively cancel or de-validate tokens, and the only way to do is by checking a black list of tokens on every user call, which kinda miss the purpose of not accessing the DB on every call.
A good compromise, in case you need a way to actively cancel tokens, is to use a fast validation method which for example can be based on Bloom Filter, and for that you might want to use RedisBloom.
Since #Guy Korland has already covered the basic idea of JWTs, I'll comment on the two approaches you have mentioned.
Should I store the JWT token as a key and corresponding user info as
value in Redis so that I can fetch info by token if valid
This approach is not very helpful if all you're trying to lookup from Redis is the user's information. This is because the user information can directly be stored as claims in the payload section of JWT thereby avoiding the call to lookup from Redis. If the claim contains sensitive information, one can always encrypt the JWT token to ensure it's not being accessed by un-intended recipients.
That being said, the downside to not having to hit the cache at all is that you cannot invalidate/refresh the tokens. In general, it's recommended that you do not have long lived tokens as it's a security vulnerability.
should I encode the user data in JWT itself and use Redis only for
storing valid tokens
This is better than the previous option and it works if the user's information is encoded as part of the JWT token. Also, you can store the 'context' of the token as the value in Redis (key being the JWT itself). The 'context' here means the last time the token was used (lastAccessTime), expiry interval, etc. Using this 'context' you can determine whether the session is active/inactive and whether to invalidate the token and provide a fresh token to the client.

JWT access token security considerations

For my project, I'm implementing OAuth2 authentication framework that uses Bearer tokens.
From a quick search, it looks like JWT tokens are the mainstream choice for Bearer tokens today.
If I would use a "dumb" token that doesn't encode any information, I would be storing this token in a database, alongside all the related parameters (token's user, issue date, expiration date, etc.).
From JWT's documentation I understood that I can avoid this overhead by implementing this flow:
User authenticates with one of the supported methods
Authentication service generates JWT token and encodes the following parameters into it: user id, authentication method used, issue date, expiration date
Authentication service encrypts and then signs the token
The token is sent to the user for subsequent usage
The encryption step is desirable because I wouldn't like to advertise user IDs.
My understanding is that if I use the above method, I can avoid storing the mapping between access tokens and users, and rely entirely on the user ID information provided with the token.
What disturbs me with this approach, is that it looks like I won't have the option to "revoke" access tokens.
In other words - even if access token will become compromised, I won't be able to disable it (unless I know the exact compromised token, which is not the case).
Is this a real concern, or I'm just missing somethig? If this concern is real, how can I work around it?
Access tokens self-contained and are valid as long as the expiration time is valid. There is no specification around invalidating them in the actual spec. Depending on the level of security you need you can adjust the validation time of the tokens, from fewer minutes to hours. Typically the validation time is set for an hour.
If you require higher level of security, you can use Reference tokens. Reference tokens doesn't carry any information, they are plain strings. But, the server (or whoever is consuming these tokens) has to contact the Token Provider to exchange the reference tokens for actual response content. But, these tokens can be revoked if they are compromised.
Please refer to this link for more information and some suggestions on how to overcome some of the downsides of Reference tokens (like back channel communication/ extra round trip to Token Provider). Please let me know if you have any questions.
-Soma.

Update/change roles claim (or any other claim) in JWT

I'm storing user roles inside a JWT (to restrict API endpoints). The roles can be changed by an administrator.
If a role is changed. How am I supposed to reflect this inside all tokens? I've thought about a couple of solutions:
If I'd use refresh tokens, the user would have to wait until the expiration date of the access token is expired.
I could keep a record of changed user IDs and check every request, and then return a new token if the user has been changed.
Is there a standard way to do this?
Refresh tokens don't seem to be the solution if you care about the changes you make being instant, you probably don't want an user to access moderation tools for some time if you revoke his permissions.
What you could do is keep a version number in the jwt token relative to the user, much like how mongoose does it with it's versionKey. By doing this, you would be able to check this version against the one in the database for a given user. Each time you change the roles of this user, you would increment this version, if the version of the jwt doesn't match, just recreate a new one with the correct roles and version and send it back to the user.
I don't believe there is a proper standard for this, as jwt is immutable by design, you'll have to change it entirely if you need to "update" it.
The JWT tokens are immutable so you can't change/update claims on an existing token - thus you have to issue a new JWT token.
That leads to the biggest problem with JWT - token revocation. There are no good solutions. What you can do is
Keep JWT expiration date short (and optionally use refresh tokens)
Use a blacklist to keep a list of revoked tokens (of course losing the 'stateless' part this way)
change the secret key (keep in mind that this revokes ALL valid tokens of all users)
The best solution depends on the concrete case.
To address that scenario, you can keep the token lifetime short, once the token expires you can renew the token silently in case of Implicit grant or use refresh token mechanism to issue a new token from the authorization server. Once the role has changed, it might not reflect in the token instantly, but it will be available once the token is renewed.
#Janar said three solutions to handle different scenarios, but they still exist corresponding drawbacks.
I also have a idea to revoke your token:
set iat to JWT payload. (You should know what is the iat)
revoke tokens of a user:
find the user id
let auth server rejects tokens which are before current time(judged by iat) and belong to this user(judged by userId)
A solution to this would be to keep authentication and authorization separate when using JWT tokens. Use the token for authentication(claiming an ID) and use that ID to check the authorization in the database. This can increase the latency of each request considering that you now have to check the authorization for each request. However, this can be mitigated by using an in-memory data structure store(such as Redis) as a cache. On every permission change, delete the cache and make another call for the permissions.

Manually expire JWT token from server - WEB API 2

I am working on a api server which revives requests from a mobile app. I am using JWT with ASP.Net MVC Web API 2. In this Admin gives access of various departments to mobile app users. I set these DeptIds in Claims at the time of Login. On every authorised request from app, in a custom action filter attribute I read claims to match deptId in request URL with claims. This all scenario works fine.
Now my problem is, when Admin revokes access of any particular dept from app user, how should I expire the access_token of that user so that, on Login request call, I can set new Claims. Otherwise, as Admin removes access from server but the deptId still exists in user's Claims so user still have access to that department.
One way is on every request, check in database for access but that increases overhead of server also increases response time. So I don't want to go this way.
I didn't find anything on web how to expire token in JWT. Can any one help on this?
A JWT token happens to be a kind of token that allows it to be self-contained i.e. one can validate it without consulting an external entity.
That also means that there's no external entity that will tell you that the token was revoked or expired. Expiration can only happen by some property in the JWT itself; the exp claim was standardized for that purpose: it will tell the recipient the time after which the information in it must no longer consider to be valid
Authentication and Authorization are different things.
Use JWT for Authentication but not for Authorization. I mean that using JWT you can know who the user are but don't put information about what user can do into the JWT. Check permissions for the user on the server side basing on just user's identity that you got from JWT. You may also put into JWT some information that additionally limits access rights (i.e. blacklisting; for example, social network site creates an access token for a game to access my identity and friends list but not my posts) but don't put there information that directly provides access to some features (i.e. whitelisting). In that way you can easily remove access to some features on your sever-side despite that fact that the user is already logged in with JWT.
I understand you are interested in revoking or invalidating tokens instead of expiring them.
Revoking or invalidating tokens
Unfortunately​ it's not possible to achieve it
without keeping the track of the tokens somewhere:
Issue a token and add it to a whitelist to keep the track of it.
When validating a token, check the whitelist and refuse the request if it is not whitelisted.
To revoke or invalidate a token, remove it from the whitelist.
This security schema require some trade-offs. Deal with it.
Performance considerations
Regarding your performance concerns: Bear in mind that premature optimization is the root of all evil. You shouldn't optimize until you have a performance problem and you have proven that the performance problem comes from the way you store your tokens.
You could start storing the tokens in the database and then consider a cache in memory, for example. But always be careful when fixing a problem that you currently don't have.
Token identifier
The jti claim should be used to store the token identifier on the token. When validating the token, ensure that it's valid by checking the value of the jti claim against the token identifiers you have on server side.
For the token identifier you could use a UUID.