I plan on using JWT for my login system for mobile devices. There is no real standard workflow for refreshing JWT tokens I could find so I created this one below. The reason I want to use JWT is for performance reasons. Instead of checking if a user is valid with a database call for every single request I trust the JWT.
I have the proposed workflow which I want to implement into my app. Is this acceptablly secure? Efficient? Are there any obvious problems I am overseeing? What reasonable improvments can be made?
User logs in
If no HMAC signed token exists inside of localstorage, the user gives a name to the device.
DeviceName gets sent to the server where it is inserted into database.
JWT token + HMAC signed token of the DeviceName are sent back to user. The HMAC signed token is put in place to make sure the jwt token (containing DeviceName) is sent from the same device that called it originally.
JWT token is valid for X hours so a user can make any calls for X hours.
After X hours, the JWT is expired. When a request is made the server can see the JWT is expired. Server will now attempt to refresh the JWT token. Server checks the database to see if the DeviceName specified in the HMAC signed token is the same as a valid device name in the database for that user.
If so, create new JWT valid for another X hours, if no, send back message to require login.
If an account is compromised:
User can log into my password service. Once logged in, I would retrieve all the devices for that user, the user can then revoke their compromised device. Once this is done, a request to refresh the JWT will not work with the stolen token.
All of this of course happens over SSL.
My concerns which I have no solutions for:
If a JWT token is stolen the attacker has X hours to make calls based on the victim. I think this is the nature of tokens though and an accepted risk?
If the JWT is stolen, that means there is a good chance the HMAC token containing the device name is also hijacked so the user could refresh tokens until the victim realizes their account is compromised and revokes access. Is this accepted practice?
The first rule of crypto is “Don’t roll your own crypto” https://security.stackexchange.com/questions/18197/why-shouldnt-we-roll-our-own
So have a look at the variety of libraries available on https://jwt.io
I’m not a crypto expert, so I’m not going to say you plan/workflow correct or there are no flaws.
However some general comments:
1) What happens if I label two devices as ‘computer’?
Have you considered what happens if everyone calls a device ‘phone’? Will everyone have the same HMAC device token?
5) After X hours the JWT token is expired, isn’t this too late for refreshing, define a clear refresh window.
E.g. Token expires after X hours and then can not be refreshed, attempt to refresh it after X-1 hours.
Your first concern: Once a token is stolen, its too late.
The aim is to secure the token so that doesn’t happen in the first place.
Your second concern:
If I managed to get one of your token, assume I got both.
If I have your token(s) I am you, and I can refresh the token.
You could consider having a max expire or max number of refreshes to limit this.
Related
I've been doing a lot of reading on this subject and I can see that there are many different opinions and approaches to authenticating using JWT.
My understanding is as follows:
In its simplest form, a JWT authentication mechanism should:
Verify username and password.
Create a signed JWT access token containing information (depending on the app's needs) on the user.
Send that token in the response.
The client then stores the token (which from my understanding there is some debate whether a secure cookie or localStorage is more secure), and sends it with each request's headers.
The server can then authorize the user using middleware verifying the JWT. No state, all information in contained within the JWT.
Assuming the JWT has no expiration (or perhaps a very long expiration date, maybe a couple of months), it sounds good because I can provide the user a persistent logged in state for a long time. The concern is, to my understanding, if the JWT was to be stolen, it is essentially an unlimited access card and a huge security breach.
So that's where the refresh token enters, the server issues both refresh and access tokens (refresh token with a long/unlimited expiration and the access token short).
The server database holds some kind of table of valid refresh tokens (so that if one is stolen it can be invalidated easily) and when issuing a new access token, validates the refresh token.
This also adds the need to add some sort of countdown mechanism on the front end where a refresh request is to be sent to the server prior to the access token expiration date so that the user won't be logged out.
And my question:
Why? If we go through all the trouble of creating a db table for refresh tokens, why not just make a table of valid access tokens and invalidate them if needed? How is that less secure than using refresh tokens?
Thank you
Access tokens aren't primarily used to provide extra security, but to provide efficiency and decoupling.
An access token can have a very short lifetime - maybe even less than a minute - but be used to authenticate multiple requests to different services within that time. Those services don't need to have any access to the authentication database, because they can trust the access token until its expiry date; that makes them faster and simpler.
For instance, if you're using a dynamic page with lots of AJAX requests, that might run in very quick succession. Those AJAX calls might be implemented as serverless functions (e.g. AWS Lambda), or as standalone scripts in different programming languages on different servers, or you might just want to make them as efficient as possible, and avoid any database access. The only information that needs to be shared between them is a public key to verify the signature on the JWTs they receive.
From a security a point of view, this is a trade-off: on the one hand, an access token for a user whose access has been revoked can still be used until it expires; on the other hand, the long-lived refresh token is transmitted much less than a traditional session token, so there are fewer chances for it to be intercepted.
To address your concrete concern:
This also adds the need to add some sort of countdown mechanism on the front end where a refresh request is to be sent to the server prior to the access token expiration date so that the user won't be logged out.
No "countdown" is needed. The code that has access to both tokens simply looks at its current access token before using it; if it has expired, or is about to expire, it requests a new one using the refresh token. It then gets a new access token, and probably a renewed refresh token - the expiry date on the refresh token represents how long the user can be idle before they are automatically logged out.
We don't need to make a table of access tokens and it is dangerous to secure.
We have to save only refresh token and add one field for valid/invalid in the table. And send access token and refresh token to the client side.
The clients send access token with each request's headers.
The server can authorize the user using middleware verifying the JWT.
After some time, the access token will be expired(access token's expired time is shorter than the refresh token's expired time).
The client sends refresh token to server.
Then the client will get new access token using refresh token(refresh token should be recreated, in other words, we can use only one-time refresh token, we have to update table of refresh token with new refresh token).
The client can get new access token and refresh token.
I hope it will be help you.
I am implementing JWT inside a client mobile app with a separate back-end server, and I am looking for an optimum way to use refresh tokens without too much server calls and while keeping a good user experience.
I am new to implementing such a mechanism, and I am confused about many things, so what I am really looking for is a solid conceptual solution to secure the user access to the app, and keep him at the same time logged in indefinitely.
Any correction or suggestion would be most welcome:
Why refresh tokens anyway?
Using a JWT access token alone might compromise the user security: If an attacker holds the access token, he might run feature requests whenever he wants. Even when applying an expiry date to the access token, if the server issues a new access token whenever the old one expires, the attacker will receive this new access token using his old one, and keep accessing the user features.
Refresh tokens stop the attacker once the user regains access to his account using his login/password: When the user uses the app and the server detects that his refresh token is invalid, he will be logged out and a new refresh token and access token are issued after he's logged in with his credentials. The attacker won't be able then to use the old tokens.
My first question would be:
I. Regardless of how the attacker gets hold of the tokens from the user environment, would he be able to use them indefinitely as long as the user is still inactive and isn't logged in again with his credentials to create new tokens?
What about when the tokens are refreshed asynchronously?
Let's imagine a scenario where the user is inside the app, and at least two server calls are run asynchronously:
"Service1" makes a server call with an expired accessToken1 and a refreshToken1, and the server responds by sending a new accessToken2 and refreshToken2
Before receiving the "Service1" response, "Service2" makes an other server call with accessToken1 and refreshToken1, the server compares refreshToken1 to the previously saved refreshToken2 and finds them different. It responds then with an Invalid refresh token response, and this causes the user to be logged out!
To avoid this problem and keep the user logged in, there could be a centralized authentication service that checks first the validity of the tokens before any server call is made. Which means that any call won't be executed unless the authentication service is idle, or wait for the new tokens if it's already loading.
My second question here is:
II. Having such a service to avoid the asynchronous refresh token problem means more round trips to the server, which might prove costly. Is there a better solution?
There are some steps to login / revoke access to an api:
When you do log in, send 2 tokens (Access token, Refresh token) in response to the client.
The access token will have less expiry time and Refresh will have long expiry time.
The client (Front end) will store refresh token in his local storage and access token in cookies.
The client will use an access token for calling APIs. But when it expires, pick the refresh token from local storage and call auth server API to get the new token.
Your auth server will have an API exposed which will accept refresh token and checks for its validity and return a new access token.
Once the refresh token is expired, the User will be logged out.
JSON Web Tokens are a good way of securely transmitting information between parties. Because JWTs can be signed—for example, using public/private key pairs—you can be sure the senders are who they say they are. Additionally, as the signature is calculated using the header and the payload, you can also verify that the content hasn't been tampered with.
What about when the tokens are refreshed asynchronously?
that supposed be done with a single request to an endpoint, so there is a single accessToken
Having such a service to avoid the asynchronous refresh token problem means more round trips to the server, which might prove costly. Is there a better solution?
i think that's the best & secure solution for mobile and serverless apps, token are like ssh keys must be kept secure all the time :)
for more information check [question]: JWT refresh token flow
Here's the official introduction to JWT
I'm building a nodejs server with jwt authentication.
At the moment my jwts have a expiration time of 1 month.
If the user goes on the loggin page, I check if his request contains a valid jwt, if yes, he don't have to type in his username and password.
If he logs out, the jwt gets deleted on the clientside, so the user have to log in next time with his credentials.
What if an attacker listens to the connection (I'm already using ssl) and gets the token.
Even if the user logs out and gets a new token on his next session, the attacker can impersonate the user with the old token, as long as it is valid right?
Is it a good idea to store the IAT of the "current" token of the user in the DB and compare it to the IAT of the token in the request to avoid the access of the attacker?
I know, 1 month is quite a long time for a jwt. I also had the idea to generate a new token, every time the client logs in (with exp. time 2 days). But if an attacker gets only 1 valid token, he also gets the new tokens, isn't he?
Do you have any suggestions?
Thanks, Cheers!
Your concerns are exactly one of the reasons that security people advise against using JWTs for session data -- see section "You cannot invalidate individual JWT tokens". In other words, the only way to invalidate JWT tokens is to force a database lookup when it is presented -- but that defeats the entire point of the JWT in the first place (most people use them because they are trying to avoid a database lookup on the server).
Store the tokens and any session data (for example user ID for the logged in user) on the server. This gives you full control of the data, and the sessions. It also removes a lot of avenues for abuse (which the JWT standard allows).
When doing that, if you know a token is stolen, you can simply mark it as invalid on your server, and have your application ignore it.
In practice, this means just having a token in the cookie, and having the user ID and other session data stored in a database table or server side cache (for example a mysql table or redis cache).
I was going through Oauth2 docs and thought it was kind of permissive security wise, so i tried to implement JWT tokens with a special scheme like in the picture for a mobile app communicating with a web API.
Notes : i didnt like Oauth2 refresh tokens idea as they might get stolen and allow parallel usage (by legit and malicious users) unless you implement theft detection by rotating them (refreshing refresh token upon each request) in this case why use them at all ?
How the auth flow works :
A user logs in with credentials gets a jwt of 20 minutes lifetime.
Upon expiry the jwt gets refreshed by hitting the db checking if it's blacklisted (relogin) and if not check if it was used to generate a new token.
If it was never used to refresh it is accepted and used to issue a low grade access token.
If the token was used before, or had different client+device+user than its parent offer a credential check (password or lockscreen code)
If passed, this check issues a new first grade token that blacklists all its parents and children on the db, its like a new first user login.
If lockscreen fails the user is presented with login screen.
The questions are :
What are possible security holes ? (I found two use cases : stolen valid access token lasts 20 minutes same issue as Oauth tokens. No gain no loss here. And stolen sleeping token : user not logged in for say 7 days, token gets stolen and used until user logs in again or token chain revoqued after 3months of persistance - our policy - and this theft has small chances since token has to be intercepted at the last request the user makes on the app , slimmer than stealing an Oauth2 refresh token )
What are user experience problems an attaker can cause on the app while on this scheme ?
OAuth2 refresh tokens are not meant to be used by mobile clients. Using refresh tokens requires client credentials, which cannot be stored securely in a mobile application.
Refresh tokens are used from confidentials clients (server side web applications for example). They are often renewed when used (server sends back new access and new refresh token). In contrast to access tokens, the refresh token is only sent to the authorization server, not the resource (API) server.
Regarding your auth flow. Step 2 is the weak link IMO. You allow the client to use an expired token to generate a new access token. So if I find your phone and access the device, it will allow me to get a fresh access token and impersonate you.
You could force the client to refresh the token every say 15 min., but then you have to define what happens if the app gets closed or the device is turned off? Is it okay to re-authenticate the user again?
I am building a token based authentication (Node.js using passport/JWT with an angular client).
After the user enter his credentials he gets an access token, which he sends in every request inside the header (header: bearer TOKEN).
I don't want to prompt a login request everytime his access token expires (about everyday I guess),
I've heard about the Refresh Tokens. The refresh token never expires (or rarely expires) and able to renew tokens indefinitely.When the access token is about to expire, the client can send a renew request to get a new access token by sending his refresh token.
I don't understand few things, I might be missing something:
How a long-living/never expiring refresh tokens don't ruin the security of having short-living
access tokens.
Cookies can be stole and be used until they expire. Tokens are short living so they more secured,
but if I provide a long-living refresh token I lose the advantage of using tokens.
NOTE: I am aware that the refresh tokens are sent at the initial login, so cann't be spoofed in every request, but if they are spoofed at the initial request they are vulnerable.
The refresh token is presented on a different path than the access token: the access token is only ever presented to the Resource Server, the refresh token is only ever presented to the Authorization Server. The access token can be self-contained so that it does not need costly calls to the Authorization Server to check its validity, but to mitigate loss and to increase accuracy (it cannot be revoked in case something goes wrong) it is short-lived. The refresh token is long lived and gets validated on each call to the Authorization Server and as such it can be revoked. The combination of the two makes the system secure.
I use the following approach:
Tables/indexes:
User table (just has the user ids and all the user related meta-data)
JWT table (three fields : user_id, access_token, refresh_token)
Authentication Flow
1.When a previously unauthenticated user signs in, issue a JWT which contains an access token, and a refresh token. Update the refresh token in the JWT table, together with the user_id, and the access token.
2.Make sure that the JWT has an expiration time that is something small/comfortable for your users. Usually less than an hour.
4.When a client makes a request with a JWT
a. Check expiry of the access token. If the token has not expired -> continue without hitting any db tables.
b. If the access token has expired, lookup the user_id in the JWT table, and check if the refresh token and access tokens match, whatever the client has provided,
If yes, issue a new JWT with the response and update the new refresh token,access token into the JWT table.
if no, return 401. The client is forced to ask the user to then sign in.
END.
To summarize,
1.DB calls are required only to check if the refresh token is valid.
2.This system allows for a user to sign in from any number of devices, with any number of JWT's
3.All JWT's related to a user can be invalidated, by wiping the refresh tokens related to that user from the JWT table, this can be done, for eg: when a user changes his/her password. This, in effect, narrows down the window of compromise to the expiration time of the access token/JWT.
I believe this is the intention behind JWT's. The percentage of DB calls/user depends on your expiration time, the duration a user is usually on your website, etc.