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.
I am using the following doc by AWS for verifying the incoming token with Cognito to verify the user in cognito pool:
https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-verifying-a-jwt.html
Now I also need to verify one of the custom attributes (email) of that user. (Basically this is to mitigate a case where some user can change their email-id in the API payload to access someone else's details).
The Cognito SDK I found to do this was this : https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_GetUser.html
It works just fine, however this led me to a question :
Since I'm sending access token in this SDK, do I need to use the former jwt-based token verification as well? Because this SDK also handles the case where token is invalid/expired and sends error codes accordingly. Is there something I'm missing which the former case handles and the latter one doesn't ?
Short answer: no, you can ignore the contents of the JWT.
Longer answer: JWT tokens provide a fast way to verify that a user has been authenticated, without the need to check a database or external service. This can be very important in a high-volume application.
However, they have several limitations:
A JWT token is issued with an expiration timestamp. If you rely on the JWT, you do not have a way to forcibly log-out a user until that timestamp expires.
To be secure, your JWT token must be signed using an asymmetric keypair (I mention this simply because a lot of people have implemented their own identity servers incorrectly; Cognito does it right).
The claims that are in the token (and are signed by the identity server) may not be sufficient for your needs. Best practice is to minimize the size of the token, and iirc Cognito follows this practice by only including the user attributes that are directly tied to authentication.
If any of these limitations apply to a particular use-case (and it sounds like the third applies to you), then you'll have to make that external service call to the identity server. And if you do that, and the server reports authentication status, then there's no need to pay attention to the token.
Hey I am getting started with the serverless framework, apigateway, lambdas and authorizers.
Here my questions:
In order to verify a proper JWT token (which seems nowadays the best solution for serverless authentication), I would need a client id. Since the authorizer lambda is not capable(?) of reaching any other parameters of the request into the lambda except for the token itself, this is a difficult task to do. How can I achieve this?
Since with every authenticated call, an additional lambda is called, my costs are doubled?! May be I am misunderstanding something here, but it seems to me like implementing a method for verifying my token without using the authorizer is cheaper and I don't need to implement the authorizer lambda itself.
The whole point of OAuth2 is that at the point of authorization you don't care who the bearer presenting you with a token is or which client they are using (web app, Postman, etc.), only that the token is valid for whatever the token bearer is trying to do. You trust that the authentication has happened because the token issuer has done the authentication.
When you talk about the aud(audience) (from comments) in JWTs, which may or may not be included dependent on the JWT issuer, this is intended to reflect the service or services that the JWT is valid for.
This could for example have a value of 'myAPIName' or 'myAPIName/test' or even ['myAPIName/test1', 'myAPIName/test2'].
If you need to validate an individual aud claim you have two choices, you can either have different Lambdas authorizing different api routes and methods with hardcoded aud variables or you can get the name of the api being called and map it back to something that would match an aud claim.
For example the method arn for the incoming request can be found in event.methodArn. This looks like arn:aws:execute-api:{regionId}:{accountId}:{apiId}/{stage}/{httpVerb}/ potentially with [{resource}/[{child-resources}]] dependent on your implementation. With a bit of string manipulation, you could map this back to the format of an audience claim (whatever that looks like for you).
If you would rather work an api name instead of an api name you can use the apigateway.getrestapi method for whatever sdk you are using. Documentation on this method for the JavaScript sdk can be found here.
The JWT may have a sub(subject claim), again dependent on implementation of the JWT issuer, this could relate to any of your users (or at least the users the JWT issuer knows about). Validating this beyond checking the signature of the JWT is pointless. The best you could do is check if that user exists and only if you have access to the same user database that the JWT issuer does. Although this can be used to ensure that UserA only has access to UserA's data. Again, you are trusting that the fact a bearer has a token is proof that they have authenticated (proved who they are).
I hope that answers part one of your question.
In regards to part 2, the advantage of using a Lambda Authorizer over doing the authorization in the target Lambda is caching.
So envisage I have a token valid for one hour and I call your API once every second for 30 minutes (1,800 calls). You have a Lambda authorizer with a response cache time of 10 minutes. That means you check the JWT 3 times for 1800 api calls.
But if you do the validation of that token in your target Lambda, you are doing that processing 1,800 times.
There is authentication with AWS Cognito which will allow you to use authentication outside your application and still being able to let your application divide the users into subgroups based on custom roles or similar.
If for some reason you cannot use AWS Cognito (Why not?) there is both the possibility of custom authentication (the same for each function with SLS) or even authenticating with custom code inside each lambda function.
I would recommend to use Cognito, and only custom if you know you need it.
I am starting to work on an authentication system for an angular 2 Single Page Application using django-rest framework as back-end. I'd also like to have some kind of "remember me" functionality that is going to keep users logged in for a certain amount of time.
From what I have read so far, it seems that the best authentication method for this kind of Angular 2 SPA/REST API is using jwt (json web token). For jwt authentication, I looked at the django-rest-framework-jwt (https://github.com/GetBlimp/django-rest-framework-jwt).
The problem that I see is that the token needs to have a short life span (few minutes to a few hours...) in order to minimize security issues if the token get stolen. The token now needs to be refreshed frequently to avoid the user from being disconnected while using the application. In this case, a "remember me" functionality is posing problem since the token have a short life span.
I thought about a solution involving a second token that would serve as a refresh token. It would be opaque, have a longer life span and would contain information specific to the user (ip address or something like that) so that if it get stolen, the information specific to the user being different would render this refresh token invalid.
So here are my questions:
1- I would like to know if they are existing solutions addressing this problem. As any security/authentication issues, I prefer to rely on well tested solutions to avoid getting my API compromised.
2- Would the refresh token based on specific user infos be a good idea?
3- Any other ideas how I could implement what I want?
For your situation, you really need a way to store issued tokens.
I always use an OAuth2.0 server setup that manages the auth and returns tokens the OAuth setup uses a database to manage everything so it's easy to manage and revoke tokens.
The database schema would be like this http://imgur.com/a/oRbP2 the problem with using just JWT without any management over the issued tokens with long expiration you have that security issue of not being able to revoke easily.
I would advise against including any such thing as a password in the JWT and requiring them to change it what if they use that password everywhere, then they would have to change that everywhere.
Updated from comments
Sessions Authentication use session_id which most the time is stored in a cookie and this is attached to every outgoing request. It is stateful. It is nothing more than a unique identifier that associates a user account that the server has in memory/database. For example, this can course problems when running multiple servers/instances when scaling your infrastructure.
Token Authentication no session is persisted on the server so this means it is stateless. It normally uses the header Authorization: Bearer REPLACE-WITH-TOKEN . This means that this token can be passed to multiple different servers/instances because the authentication is not limited to the server that you initiated the authentication on. This helps with scaling your infrastructure. Tokens can also be passed to other clients.
RESTful API's are stateless so there must not be a session state stored on the server. Instead, it must the handled entirely by the client so that's why token authentication is used.
I had the exact problem when trying to use JWT with an application that needed a lot more than JWT was designed for. OAuth2.0 has a lot more options that I believe are necessary to meet your requirement in the safest manner possible and even features that you may find very useful in the future as your Application may grow and need more features with regards authentication.
Actors
Front-end (fat client-side Javascript application) which has Facebook access token.
Back-end which 100% relies on OAuth2 authentication. All requests need to be authenticated via Facebook.
To mutate user data on the back-end, I require user to be logged in via Facebook. Ideally, with every request, I would know the Facebook's user ID (the one that graph.facebook.com/me provides).
Question 1
Is there a way to get whatever graph.facebook.com/me returns to be signed, so I don't have to call Facebook to verify it with every request, nor store state in my backend?
Situation 2
If the answer to Question 1 is "no", it means I have to invent my own. I am thinking of the following:
The user sends the access token to the backend.
Backend calls token debug API, signs the result with my key, and sends back to the client.
Every time client does a request, it includes the previously-included blob.
Upon every incoming request to the backend, it verifies the signature, which, if matches, means that the request wasn't tampered with and I can trust it is coming from the previously-verified token.
Question 2
If I employ this scheme (sign the answer from Facebook and send it upon every request), how can I safely implement this? Are there resources I could read up which would tell me:
Things to be cautious about with this scheme.
Which signature algorithm to use, how to safely verify the signatures.
How to avoid common types of attacks and stupid mistakes.
Thanks!
It's not really clear what exactly you want to do, but I think you should have a look at the docs at
https://developers.facebook.com/docs/graph-api/securing-requests
Quote:
Graph API calls can be made from clients or from your server on behalf of clients. Calls from a server can be better secured by adding a parameter called appsecret_proof.
Access tokens are portable. It's possible to take an access token generated on a client by Facebook's SDK, send it to a server and then make calls from that server on behalf of the person. An access token can also be stolen by malicious software on a person's computer or a man in the middle attack. Then that access token can be used from an entirely different system that's not the client and not your server, generating spam or stealing data.
You can prevent this by adding the appsecret_proof parameter to every API call from a server and enabling the setting to require proof on all calls. This prevents bad guys from making API calls with your access tokens from their servers. If you're using the official PHP SDK, the appsecret_proof parameter is automatically added.