I've been doing some research on implementing JWTs for a PHP based API we are building and one thing that confuses me the most at the moment are refresh tokens. From what I gather, you get both an access token and a refresh token during initial authentication and that the refresh token will allow you to basically skip this initial auth step to get you a fresh new access token when needed. If I understand this correctly, refresh tokens when generated need to be stored in a database paired with the client that just authenticated itself. If my access tokens only live for an extremely short amount of time (say 1 minute), does that mean that a very busy client using the API could end up querying my data store every minute to do the refresh step (to check if the refresh token exists/is still valid/has not been revoked/etc)? Wouldn't that be close to being just as bad as hitting my database with every request?
If your access tokens lives for a short time (1 min) you will need to generate a new one every minute, if of course user stays for longer than minute. Refresh tokens dependly of configuration can:
Expire after first use
Expire after given amount of time (f.ex. 14 days), so with one refresh token u can generate many access tokens
Never expire, can only be revoked (f.ex. by generating a new refresh token)
In your case I think you can use Memcached to store for each user his own refresh token. But if may I ask, what's the reason, that your access token has to expire after 1 minute?
For example, first you can check if refresh token exists in your Memcached, and if not add it to Memcached and use it after it.
Example
<?php
$m = new Memcached();
$m->addServer('localhost', 11211);
$user_id = 1;
$refresh_token = $m->get($user_id."_refresh_token")
if (!refresh_token) {
if ($m->getResultCode() == Memcached::RES_NOTFOUND) {
$token = 'Some SQL query to get refresh token';
$m->set($user_id."_refresh_token", $token );
$refresh_token = $m->get($user_id."_refresh_token");
} else {
/* log error */
/* ... */
}
}
The Access Token is like a DB cache for your user DB, and the expiry time is the TTL for that cache entry. Think of the expiry time on the Access Token as a heart beat of how often to validate the user against the user DB. If you get to high load on your user DB, you just increase the expiry time on your Access Tokens.
Your Refresh Token may be a JWT too, so you don't need to look that up in a DB/memcache. Normally when an Access Token expires, you check that the user account is not locked, that the user didn't changed the password etc. If everything looks ok you issue a new Access Token.
Related
I’ve been spending hours and hours on this, this is the first time I am using JWT and would really need some of your thougts.
Right now I store my tokens in separate httpOnly cookies (my access token expires after 15 min and refresh token after 7 days).
I have read that the most secure way to store the tokens is actually using a cookie for the refresh token and in-memory (like in a variable) for the access token.
While I understand this is secure, I do not really understand how it would work in practice. Would it mean that we have to create a new access token with our refresh token on each request? Or is there a way we can make it valid and copied to new variables until it is expired?
I am using react and node btw.
I spent days reading about this too.
From what I gathered a solution would be something like this:
User logs in with login and password.
Server generates a refresh token long lived to be stored as an HttpOnly Cookie, preventing XSS attacks as it can not be accessed by Javascript.
Ideally some sort of blacklist can be used server-side to prevent re-use of refresh tokens that have not reached their expiry but have been replaced.
Generate an access token which can either be stored in localStorage or in-memory (in a variable). The access token has a short expiry life of a few minutes.
If stored in localStorage, the token will not disappear on a reload of the page/browser (F5). It will also be visible in the console/storage.
When using localStorage to check if user is authenticated, the code will try to read the token from localStorage, jwt_decode it and set a user variable with the data that is in the token.
As tokens are not encrypted, just base64, their values can be changed in the dev console. A page that is "role: admin" only will be rendered if the permission is changed. The API will be responsible to check for permissions and reject the request if the token has been tampered.
Afaik, if it is stored in a variable it is a little less visible, it also gets wiped when reloading the page/browser.
When using a variable, to avoid refreshing the access token on every request, we can use the Context API, by creating a Component with the authenticated user context that will wrap the App/Router and then on every page that needs to be protected import and use this context and redirect if needed.
When the access token is not valid anymore, because it has reached its expiry, or because it has been wiped, the API call will get rejected. Intercept this call then call the API refresh route to use the refresh token to generate a new access token.
I use axios with axios interceptor to intercept the failed request, call the refresh route, set the renewed access token, then retry the failed request. (needs to be a GET request to avoid CSRF errors apparently).
In addition (not in place of), a setTimeout can be used to automatically refresh the access token every X minutes to prevent letting it expire.
To log out, remove the cookie (eventually blacklist) and wipe the context / localStorage.
Using axios, axios.defaults.withCredentials = true; makes sure that the cookie is sent with the requests and { headers: { 'Authorization': `Bearer ${access_token}` } } makes sure the access "bearer" token is sent with the request. These can either be set as defaults for every request or per request hence these 2 syntaxes.
Github example with Flask and React
After doing some research in using JWT with Access Token and Refresh Token for authentication. I understand this in this way.
After login, return to user Access Token and Refresh Token (using same technique JWT for both).
Saving Refresh Token in Database (one User can have multiple Refresh Tokens for multiple devices).
Whenever user sends a request with invalid Access Token, check Refresh Token and call another api to get new Access Token (doing this in client side). After that, call api to get data again with new Access Token.
If Refresh Token is invalid, deleting its record in database and user must to login again to get new Refresh Token.
Does I understand Access and Refresh Token technique correctly? Please give me some advices. Thank in advance.
Of the 4 steps you listed, some look more or less correct while others do not. I will begin this answer by giving the premise for why refresh tokens were created and what is their main purpose.
Using the JWT pattern with only access tokens, there is a potential usability problem when the JWT token expires. Consider as an example a banking website. When a user logs in, he receives a JWT token with a certain expiry (typically stored under the exp key in the claims section of the token). If the token is given say a 5 minute expiry, then from a usability point of view, it means that the website would have to force the user to manually login every 5 minutes. Obviously, this is not the best user experience, because it means that a user who happens to be in the middle of some business process when the token expires might lose all that work. This is where refresh tokens step in to alleviate this problem.
Using the JWT pattern with refresh tokens means that the user receives both an access and a refresh token. A typical workflow here might be:
After login, return to user Access Token and Refresh Token (using same technique JWT for both). The receiver notes when the access token is set to expire (say 15 minutes).
As the expiry of the access token approaches (e.g. 10 minutes), the UI will send the refresh token to the backend to obtain a new access token (and refresh token). This could be done explicitly, e.g. on a website which displays a popup asking if the user wants to continue. Or it could be done in stealth mode, with a REST call being made under the hood to get the new access token.
For the edge case where the refresh token cannot be used to obtain a new access token, then the very next user action which requires authentication would fail. In this case, the user would have to redirected to the login page. But, as this case should generally be rare, it does not disqualify the refresh token pattern.
I would also point out that storing the access/refresh tokens in the database largely defeats the purpose of the JWT pattern. One major reason for using JWT is that it pushes the user session state out of the application and onto the user. By storing tokens in your database, you are totally making your user sessions very stateful, which has all sorts of potential drawbacks. Consider using the suggested workflow above to avoid doing this.
The way I see it, your refresh token needs to be stored and associated with the device and the user.
Example:
User Logs In in Device A
Call Login endpoint
Validate user is valid
If valid, generate a refresh token associated with the userid & device
id
store required data to your table or storage engine (user_sessions..etc)
user_id | device_id | refresh_token | expires_at
Return the payload with access_token, refresh_token , access_token_expires_at, refresh_token_expires_at
Front-end, store the payload
when consuming a resource, check the following
If refresh_token_expires_at > now then logs them out , show your session is timeout (or you can have a never expired refresh_token.. ex. refresh_token_expires_at can be 0)
if access_token_expires_at > now then call refresh token endpoint along with your payload.
on the refresh endpoint, validate the call and check the refresh token against the data stored.
if refresh token is valid for this user+device, generate a new access_token
return the access_token and its expires_at
If the refresh token is INvalid , return invalid
front end will log the user out.
** in any case, if a refresh token was compromised, it will be only for that particular device/user. A user can then deactivate or remove the device from their list. This action will invalidate the refresh_token on their next refresh call.
To begin with this is how my current auth flow looks
User logs in
User gets a refresh_token assigned and stored in the database (long lived 7d)
Client receives an accestoken (Short lived, 2h), and stores it as a cookie. Client also receives the userId AES encrypted, and stores
it as a cookie.
As far as the access token is not expired, the user keeps using the token to navigate the website
The token expires
The expired access token gets send to a refresh endpoint, so is the userID (Aes encrypted) both currently stored in out cookies.
The server decrypts the userId and retrieves the refreshtoken that corresponds to the user by selecting the refresh token from the database using out userId.
Now we have in the server our refreshtoken and accestoken, so we refresh the token, and send back the new accesstoken. We also generate a new refreshtoken and overwrite our old refreshtoken in the database with the new one.
My question is basically related to that last step. Since those refresh tokens are still technically valid, since they have a long expiration time. Can I create a table in my database named "blacklisted_tokens" or something like that, and store there the values of the token? And then right before generating a new access token it should prior to that check if that refresh token is or isnt in that database, meaning that it will be blacklisted.
This is the authflow diagram
My question is basically related to that last step. Since those
refresh tokens are still technically valid, since they have a long
expiration time. Can I create a table in my database named
"blacklisted_tokens" or something like that, and store there the
values of the token? And then right before generating a new access
token it should prior to that check if that refresh token is or isnt
in that database, meaning that it will be blacklisted.
it's not recommended to do that as because, probability of generating 2 same token is low and adding NOT necessary additional processes to your back-end is not a good idea and has performance issue in large scale Token re-generation(a lot of users).
And also, Tokens are along with an identity(id) in which reduces security risks.
if i were you, i would just re-write new-token to old-token.
The most important type of cyber attack which threaten Tokens is The Sniffing attack and by doing below steps actually the probability of this attack goes almost to zero:
SSL certificate
Expiring Token and re-generation
Salty requests
Salt
In cryptography, a salt is random data that is used as an additional
input to a one-way function that hashes data, a password or
passphrase. Salts are used to safeguard passwords in storage.
I'm beginning a Single Page Application, and I'm using JSON Web Tokens to Authenticate client side (JS Client with Server API).
In my app, user provides credentials (app auth, facebook, google) and then server checks for user existence and returns a token.
Client JS adds token to each request in order to use the Server API.
When token gets issued, it has an expiry time and a max refresh time. If a set a short expiration time for the token and a "good" max refresh time I get into having to know when to refresh tokens. Best approach I've found so far, is to check on client when the token is being expired (5 minutes before) and then issue a refresh request. Then I'd get a new token. This could be done till max refresh time is reached. Then, user should have to reauthenticate.
Another approach I've seen, is that on server, if token is nearly or has just expired, it gets auto-refreshed and returned to client (which has to detect token change and store it)
But... what is the difference between this and having a single token that is long lived?
Is having a short lived access token which can be renewed with a refresh token tons of times better than having a single long lived access token?
The primary reason to use a short-lived token is to defend against session hijacking, when an adversary, through one method or another, steals session credentials (in this case, the token) and acts maliciously in the victim's session. The shorter-lived the token, the less time the attacker has to carry out whatever malicious activity they have planned.
we're working on some Azure-related script using ADAL for authentication. I'm working on the code for refreshing the access token, and would like to test this without having to wait for 60 minutes until the access token expires. Anyone know if there's a way to reduce the token lifetime to ease testing scenarios?
If you are using ADAL the refresh logic is already provided by the library automatically. Whenever you call AcquireToken* ADAL will either return the cached token if present and still within validity range or use the refresh token to get you a new one. For that reason, there are no knobs for getting a new access token before its validity expires. You can use experience modifiers (like PromptBehavior) for ignoring the cache, or you can surgically delete the cache entry for the token you are worksite its, but both approaches will result in deleting the refresh token too and in a prompt to the user.