At my organization, we're moving towards a modular software architecture.. We're still in the beginning phases, and are currently working on the User Authentication (UA) module.
I'm looking for information on best practices in terms of a User Authentication module.
My current notion is the following:
Client queries UA module with login details
UA module checks login details. If they are valid, the UA module creates & stores access token, associating the token with the validated user's unique ID.
The token is sent back to the client. Client stores the token.
Whenever the client requires authentication, it queries the UA module with the token. The UA module returns the user's unique ID if the token is valid, or returns an error code if the token is invalid.
I would appreciate any criticism on those methods.
I'm also interested in knowing how to deal with the accumulation of tokens. Obviously if a user chooses to log out, the token is removed.
My notion is that tokens should have expiry dates associated with them, and a worker process should clean these tokens up at a regular interval. Is this the right way to go about things?
Please comment! Reference documents are also appreciated.
You can store the token in a DB field along with issue timestamp, with an one-to-one mapping with the client ID. So when you have reissue a token, you overwrite the old one. And when user logs out, null out the token.
When the User sends a request with the token, see if the token is past expiry date (i.e. current time > issue time + expiry time period). This would save you from running a Worker to clean up old tokens.
Related
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 building a Django Rest Framework API which is using JWT authentication. I had created access tokens and refresh tokens and sent them to users.
I also have a refresh token endpoint that will take old refresh token and generate new pair of tokens and send to user.
I have doubt in its behavior related part. Currently what I can see that whenever I create new pair of access and refresh token using previous refresh token, the old access token is also working and new one is also working.
However once when I was using OAuth2.0 (in different case), I observed that in that case the old access token won't work if we had created new refreshed tokens.
But in case of my implementation of JWT in DRF this thing won't happens. I am not storing token in database.
So I want to know that is this any implementation specific problem or is it the property of JWT only, and if it is property then please share some details over it with me.
Thanks.
According to JWT introduction:
JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed. JWTs can be signed using a secret (with the HMAC algorithm) or a public/private key pair using RSA or ECDSA.
One of the value, that you can encode is 'exp' which states for expiration date. That's why your old tokens do not expire, cause they expiration date is still valid, and any other claims didn't change. Idea behind the 'refresh' token, is to provide new tokens with bigger exp value. Saying other way, you should not expect that the authorization will fail now, as the old token is still correct one.
As well you store nothing in the database (about this I also suggest to read answer provided by #sdoxsee
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 ...
Conceptually, I really like JWT as it is in line with the statelessness of REST etc (no state saved server-side, all relevant data is contained in the token).
What I am unsure about: how would you handle token expiry when not connected (ie, a "remember me" functionality)?
There's an emerging coverage of JWT on the web, but I couldn't find anyone that answered the expiry question yet.
Clarification: I am not asking how to handle a token soon-to-expire, but what to do when a token has already expired (user closed website/app for a while). The simplest solution that comes to my mind is caching the user's credentials, which is rather insecure.
There isn't a black and white answer to the given problem of how to implement the remember-me functionality theoretical wise. Lots of theoretical arguments are given on why something should not be done, while at the same time there is no clear answer given to the problem as for how it should practically be done.
Remember-me implicitly comes with the problem that you need a longer time window of token expiration, there is just no way around this. The most secure way is to have the user login regularly given brief expiry; nobody practically likes this though, so a tradeoff is made where theoretical secure perfection is weighed against practical measures.
The way this tradeoff works is by patching the imperfections that come with having a long expiry for a token. But make no mistake about it, you will need a jwt / cookie with long expiry (whether you use two tokens, implement some secondary refreshing mechanism or whatever, at the end you run into the same problem)!
Based on articles I've read on how others did it, this is how it's done.
The way I will implement this is by offering a 3-month expiry on a jwt stored in an httpOnly / secure cookie when the user checks remember-me.
On logout just clear the cookie.
Obviously protect using https / CSRF measures on top.
If you don't agree with it, stop fussing and offer an alternative solution - which there clearly isn't from the infinite number of discussions I've read on it.
If there were a straightforward solution to the problem, there probably wouldn't be so many discussions about it in the first place.
Edit:
You can use a refresh token mechanism, but it only works if you verify the time intervals when the refresh token gets used. For example, depending on the lifetime of the access token, you can govern how often you allow a user to refresh the token. If the intervals show suspicious activity, you should revoke both the tokens for all clients.
The problem revolves around the idea that either access token or refresh token would theoretically be stolen. So merely having a refreshing mechanism without additional security is essentially useless. If you can steal an access token, you can steal a refresh token too.
I am not so sure if I follow but I will write what I think.
Imagine the token as a hotel card, you pay in advance for 5 days (remember me set to expire on 5 days). I can enter the building, garage, room, etc. within those 5 days, after those 5 days, it won't work anymore.
What to do when token has already expired? Nothing at all.
Imagine I pay those 5 days and meh, I had an urgency and I go back home (with the card on the pocket). The hotel doesn't care at all, when the 5 days pass, the card is just an useless piece of plastic and if you try to use it on the hotel, it will do nothing.
So back to web development. If you offer a remember me service, you can put an expiry date to let's say 7 days. As long as the user has the token, he can access the service without any problem. If he loses the token, he needs to login again. If he uses the token and it have expired, he will need to login again too.
If he login, he gets a token for 7 days, if he doesn't use it anymore and after 20 days he comes again, he would need to login again, the server will just decline your petitions until you do so.
What I would do if you use something like angular on the frontend is to check the token validation on startup so you can have a nice user experience.
What I don't understand about your question is de caching thing though.
In addition to #Jesus answer, you can think about implementing a refresh token system: https://auth0.com/blog/refresh-tokens-what-are-they-and-when-to-use-them/
In the hotel-example, your hotel-card (access-token) would be invalid after time X, but at the reception you can use your passport (refresh-token) to get a new hotel card again.
You could store the refresh token in the database with additional data about the device the user is using, allowing him to disable the device in case it gets stolen.
Example:
first correct client login: Create a refresh token which is valid forever (until it gets deleted or invalidated)
store refresh token in database
return access token (JWT) with expiration time to client ( this token gets not stored in database)
for the next request, the client sends the access token
Now Check if the access token is expired:
5.1 Access Token not expired, all okay
5.2 Access Token expired, check if there is a refresh token in database
5.2.1 Refresh Token is in database, return new Access Token
5.2.2 No Refresh Token in database, return 401 / logout, User has to login again
Hope this helps.
You need to persist the JWT on the client so that it’s available across page loads, the most secure strategy is an HTTPS-only cookie. This will send the JWT to your server on every request and the server can check the validity of the token and reject it if it's expired. How you handle the expiration is dependent on the type of web app you have.
For a single-page application (e.g. Angular.js apps) you would want to structure the application so that it makes an initial request of the server before it bootstraps the rest of the application. If the server sees that the JWT in this request is expired it would issue a 401 response. You application would respond to this response by rendering a login form. Otherwise it would continue with the assumption that the JWT is valid and can be used to access the required resources. If, at any time, the app sees a 401 it should bring the user back to the login form.
For traditional web apps that render their pages on the server: for any request that has an expired JWT (as read from the cookie) the server should issue a 302 redirect to a login form.
I think what you are asking is how to invalidate a JWT server side for long expiry tokens (e.g. "remember me" functionality)?
I ran into this issue myself recently and ended up using a unique user secret to invalidate the token, when the user attempts to validate a token that was produced with an old secret it will fail. The username can be found in the decoded JWT pre verification.
You could probably even use the users password salt for this, that way any current JWT's would be invalidated when a user changes their password (assuming you also change the salt at the same time), this may be problematic though as the password hash and JWT's would become tightly coupled
I can think of one way, but it is not really defined the standard.
What about adding another kind of expiration date with different lifespan to the claims? With two claims, we can treat the shorter one of it as the resource access expiration date, and the longer one as the refresh expiration date, e.g.
{
"iat": /* current time */,
"bbf": /* current time + 1 hour -- expired means no resource access */
"exp": /* current time + 1 week -- expired means cannot refresh */
}
(Note: I use bbf for the shorter expiration date. No specific reason, just because it has 3 characters in length.)
So with "remember me" checked, when the user reconnects, he can use the same token to request for a new one, but not to access the resource. With this, all relevant data is contained within the token -- no extra token required.
And lastly, when "remember me" not checked, just use the same lifespan for bbf and exp.
Is there any way to use the graph api to find out when a page access token, or application token will expire?
Update: There is a new API endpoint to access information about an access token. You can find info here: Debugging Access Tokens and Handling Errors
https://graph.facebook.com/debug_token?input_token=INPUT_TOKEN&access_token=ACCESS_TOKEN
input_token: the Access Token to debug
access_token: your App Access Token or a valid User Access Token from a developer of the app.
--
You should try to make sure that you store each token's expiration time along with the access token when you get it. For a page access token, that means storing the expiration time of the user access token. If you would like to manually discover expiration times for tokens you have today, you should use Facebook's Access Token Debugger tool. However, you should not be relying on expiration times alone -- in practice, many tokens will expire much earlier than their expiration time.
Application access tokens will never expire, unless the application secret key is reset.
Page access tokens last up to 60 days (5184000 seconds), but more importantly, they last as long as the user access token that was used to acquire them. So they will be invalidated as soon as the user that you got them from:
logs out of FB.
changes password.
deauthorizes your application.
Basically, when you lose the user's token, you will lose the page's token. Instead, you should retrieve page access tokens once per user access token. If you throw out a user access token, throw out the page token. You should not be trying to store page access tokens for any significant period of time. Instead you should get them as needed and forget them when a user's session dies.
To get a new page access token:
https://graph.facebook.com/PAGEID?fields=access_token&access_token=USER_ACCESS_TOKEN
Access Token Debugger
https://developers.facebook.com/tools/debug/access_token
Does not use the Graph API... but a very useful tool for manual debugging.
There is now an API version of the debugger tool.
See https://developers.facebook.com/docs/authentication/access-token-debug/
I would like to repeat this question for the current version of the API since I've come to a situation when Facebook doc clearly does not describe what is happening:
no expiry dates when requesting a new long-lived token with fb_exchange_token
no expiry dates when requesting debug_token information (expires_at = 0)
it does reply with an expiration date when redirecting the user to the auth page for the first time, but that does not help as I cannot extract the long-lived expiration date nor it will reply with this information for the second time
The debug tool here: https://developers.facebook.com/tools/debug/accesstoken says "Expires: Never".
Try this, it worked with me. Get the token with your app and paste it in the graph explorer as the token to be used for queries. Click on the info a see the expiration date.
example image
I hope it works for you too.
https://developers.facebook.com/docs/facebook-login/access-tokens/expiration-and-extension
From the page above:
Access tokens on the web often have a lifetime of about two hours, but
will automatically be refreshed when required. If you want to use
access tokens for longer-lived web apps, especially server side, you
need to generate a long-lived token. A long-lived token generally
lasts about 60 days.