JWT refresh and access tokens - javascript

I use jwt tokens in my project. Long-lived refresh tokens to authenticate and short-lived access tokens for protected resources. The refresh token is saved in a http-only cookie to reduce the risk of xss attacks. The access tokens will be only stored in my vuex store of my frontend. Should I renew my refresh token if the user changes the password? I don't store refresh tokens in my database, because as I understood the the main purpose of jwts is that I can use cryptography to verify my incoming refresh token and do not have to look it up in my database (then I don't have to use jwts at all).
But how do I invalide an already sent refresh token e.g. on an other device or browser? If I don't use a database to store refresh tokens the token would be valid as long as the expiration time is. I appreciate any advice.

Since you don't store tokens in the database you can't invalidate them remotely. But there are some common practices to overcome this issue.
NOTE: These are not standards, Just a practice used by major
companies.
1. Store tokens in Cache Database (Not in the main DB)
Storing JWT tokens in the cache database such as Redis or Memcached will allow you to retrieve and verify the token much faster. To invalidate the token you just need to remove it from the cache.
2. Use short-lived access and refresh token
This is mentioned in a lot of Security Submits. Expert says to set a very short life (in minutes) to both access and refresh tokens. Also, exchange the refresh token every time you get a new access token. This renewing process can be happing in the background (maybe using workers). So you don't need to invalidate tokens, It will be invalidated automatically after a few mins.
Recommend you to watch this: https://www.youtube.com/watch?v=rCkDE2me_qk

Store your refresh tokens in a database, with enough context to create a new JWT token (also expiry date, allowed IPs/regions/browsers ...etc) this database will be used only by your Auth service, and only when managing auth (login, logout, refresh access token).
Storing JWT in a database introduces a single point of failure for your microservices (Assuming you are using this architecture), if you're storing JWTs somewhere it would be a simpler implementation to just use session IDs and data.
Give each JWT token an ID (it's already in the default claims), and link that ID to a refresh token
when you invalidate a refresh token, broadcast an event to all your services telling them that any JWT with the token.JwtId is invalid. this invalidates all JWTs created by that token on all services (You can invalidate by token context as well, ex: user id to invalidate all tokens for a user that were created before X)

Related

Would the following JWT refresh token flow be considered secure?

I am creating a web server for a site with authentication using JWTs. Since this is going to be a publicly available system once ready, I would like to know if the following authentication flow using JWT access and refresh tokens could be considered secure.
In this case it is assumed that one server serves both the auth API and resources
When the server starts, it will generate a "run ID" which is the current UNIX timestamp and random characters/UUID. This is stored in memory and any restart will generate a new one.
The user obtains an initial HttpOnly access and refresh tokens when logging in or registering. Access token has a short lifespan (~5 mins.) and refresh token has a longer lifespan (~2 hours).
The access token functions like normal and contains the userID.
The refresh token has the userID, the server's run ID and its own unique "token ID" (similar to run ID, unique for each refresh token)
Instead of the user calling a token refresh endpoint, new access and refresh tokens are made when calling an endpoint that requires authorisation if the following criteria are met:
The access token has expired
The refresh token has not expired
The run ID in the refresh token matches up with the current run ID
The refresh token's token ID isn't blacklisted
In the event that there is a run ID mismatch or the token ID has been put on a blackist, the refresh token is instantly considered invalid.
The token ID blacklist is stored in memory (like the run ID) as an array with the ID and expiration time.
This allows a user to logout and blacklist that specific refresh token from being used.
This also allows any system administrators to emergency invalidate all refresh tokens by restarting the server since the runID will change.
I would like to know if this can be considered a secure authentication flow
It took me a while to understand what is going on with the tokens and your motivation around it. I believe what you did here is more complicated than reality requires and there should be little reason to introduce this level of complexity. Please also note, that security in its definition is a double edged sword. It's an eternal conflict between integrity and confidentiality VS availability. If for some reason we screw the systems availability then it will not be considered secure in the same sense, that turning a computer off is not considered a solution of security issues.
Having said that, let's look into your solution.
You intend to use access and refresh JWT tokens. How should a logout in such system look like? Well, you simply forget the token information on the client side or in case you want to hold tokens in cookies - which I believe you want to have based on "HttpOnly" flag - you can clean up the cookies. This is it. Once the information is gone from the client, the tokens can not be easily recreated. There is no need to blacklist the tokens on the server. It is in clients best interest to 'forget' the tokens he is not using and once the token is gone, there is no second copy to replace it.
We use token blacklisting in case we want to deal with a scenario like real-time user account locking. An expensive thing to implement if you ask me.
You can still try to blacklist refresh tokens, but assuming your authentication mechanism has access to the user pool, it can simply check in the database if the user is locked, no need to cache anything here.
Next thing I notice is that what you did here reassembles strongly simple Http Session handling including loosing the session once the server restarts. Why not forget the tokens and use a simple session instead?
I also wonder, why you intend to have only one instance of your system. In the High Availability age and playing with JWT tokens it would totally make sense to separate authentication module from logic and have more than one instance of both.
Please also note, that no one will be able to tell you, whether what you do is secure, until they can look into your code, configuration and ideally - working system. There are many small pieces that can break the solution. Ideally have a look into the OWASP ASVS (Application Security Verification Standard) available here to see, how deep the rabbit hole goes.

insufficient session expiration in react application

i have recently encountered problem for my app with insufficient session expiration.Basically we have session storage field that contains user token , like that for some more we have tokens. On logout since we are using SSO , we are clearing user session only not other data. we have recently reported this problem.
reference
what might be the solution
To properly cancel the user's session, you should not only delete the local session token, but also cancel the token with the SSO provider.
You don't specify who you are authenticating with, but every reputable SSO provider should have a sign out or log out option which will invalidate their session at the back-end. Then you can delete the user token since it is no longer valid, and no malicious 3rd party will be able to use a session that is secretly still active.

Handling JWT expiration and JWT payload update

I have a Koa based Node.js backend for my personal/hobby application.
I implemented session handling with JWT tokens. The client (AngularJS) gets the token after a successful login and stores the token somewhere (currently in sessionStorage but for the purposes of this question it shouldn't matter).
I have two questions:
When I need to update the user record which the JWT represents, say, the user turned on Two-factor authentication (2FA) so I asked him to provide his phone number and I'd like to set this phone number in the user's record. Currently, after a successful verification on the phone number I call my backend to update the user record and I create a new JWT token with the updated user record (I exclude sensitive information from the JWT token like the hashed password, but I'd like to include the phone number for client side usage). Is it okay to create a new token when some of the credentials change and update the existing client side token with this new token? Should I never-ever create another token, only to create the one and only upon successful authentication? How do I then update the payload in the token?
How should I handle expired JWT tokens? In my mind I have 3 (possible) scenarios:
2.1. The JWT is set to short living, say 15 minutes. If the backend server replies with a 401 Unauthenticated 'Invalid token' (I guess this is the default behavior of koa-jwt) then I automatically log-out my client and require re-authentication. But I also set up a complementary middleware, which is the last in the chain on the backend to re-create the token with a refreshed expiry and the client would also replace the existing token with the refreshed one. So if the user is active and uses the application every protected API call, in case of success, would create a new token to replace the old token.
2.2. The JWT is set long-living, say 1 week, and if it expires I opt-in re-authentication from the client.
2.3. Copy https://www.rfc-editor.org/rfc/rfc6749#section-1.5. Here when creating the JWT token after a successful authentication we send an access_token as well as a refresh_token. When the access_token is expired and the server responds with HTTP 401 'invalid token' (koa-jwt default) then the client sends the refresh_token to the backend to require a new access_token (and optionally a new refresh_token). In this case I don't fully understand how the refresh_token is verified against the old access_token to provide a new token? Or why do we need to have a refresh_token?
Any generic advice on the upper topics (JWT updates and JWT expiration) would be helpful.
Starting from the bottom, I would ignore refresh tokens as I don't think they will help you here. They are generally aimed at other scenarios where the client application can provide storage more secure than the user browser -- think native mobile applications or server-side web applications.
Refresh Tokens are long-lived. This means when a client gets one from a server, this token must be stored securely to keep it from being used by potential attackers, for this reason it is not safe to store them in the browser.
(emphasis is mine; source refresh tokens)
This means that option 2.3 is basically the same as 2.2, which is not a bad option. It's not uncommon to have web applications with long session duration. If your application is not highly sensitive it's acceptable to use long session to improve user experience. For example, Django uses a default of two weeks for the age of its session cookie. See SESSION_COOKIE_AGE.
The remaining option (2.1), is usually referred as sliding session. The session timeout is short, but as long as the user keeps using the application within that interval the session gets automatically renewed. This is possibly the most common approach, or at least the one I used most time, so I'm biased. The only thing I would note is that sliding session are usually implemented with opaque session identifiers stored client-side as cookies and then with the actual session data stored on the server.
Your approach is a bit different because you have a stateless JWT token (it contains actual user data) stored on browser local storage. Like you said, in order to update the token you'll have to generate a new one, because you'll have to generate a new signature.
The signature is used to verify that the sender of the JWT is who it says it is and to ensure that the message wasn’t changed in the way.
(emphasis is mine; source JSON web tokens)
Having said all that, I would consider the following:
Ask yourself if you really need JWT's or if regular session identifiers stored as cookies (HTTP Only) would simplify your logic.
If JWT's are a requirement, for example, you have another API that will also accept these tokens as authentications, then I would consider option 2.1 or 2.2 as refresh tokens for a browser-based application are not recommended.
Having said that, you should also consider that JWT's are not huge, but they will still be an overhead if you decide to be automatically renewing. You may mitigate this a little by choosing a session duration of 20 minutes and only perform automatic renewal after half the session has elapsed.
Another point is that a vulnerability like XSS in your application will expose the access token to an attacker as the injected scripts would be able to read from localStorage/sessionStorage, this can be another point in favor of HTTP only session cookie storage.
I would like to answer your second question before I can get on to the first one.
Basically the third option which you have mentioned is the best way to renew your access tokens. Access token should be short living(~5mins) and refresh token has longer life. When your access token gets expired, send your refresh token to the backend and get a new access token. So your response should be something like this:
{
"token_type":"bearer",
"access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiVlx1MDAxNcKbwoNUwoonbFPCu8KhwrYiLCJpYXQiOjE0NDQyNjI4NjYsImV4cCI6MTQ0NDI2Mjg4Nn0.Dww7TC-d0teDAgsmKHw7bhF2THNichsE6rVJq9xu_2s",
"expires_in":10,
"refresh_token":"7fd15938c823cf58e78019bea2af142f9449696b"
}
So the idea is to seperate your application into Authorization Server (which generates access token / refresh token) & Resource Server (validate access token and access the resources ). You can maintain a schema to validate the refresh token against the access token in Authorization Server. Please refer to the schema section mentioned in this link which might give you some idea. Oauth2. You can modify the schema according to your need. You need not send your refresh token along with your access token for each request call. Refresh token can only be sent to Authorization server for generating new access token. How to generate refresh tokens? If I am using Java, I would use UUID.randomUUID() to generate a unique refresh token.
Now to answer your first question, if you want to update your JWT payload based on your updated user records, then you can use the same refresh token to generate a new access token with the updated payload. The logic remains same because if phone number exists in the user record it gets added to the payload and if not, it will be null in the payload.
The main advantage of using Refresh token is that the Access Tokens can be renewed at any time using Refresh Tokens

Angular JWT and user info storage after login

How good practise is saving any other user info except JWT in localstorage or cookie after successfull login? (User profile object is already saved and encrypted in jwt payload sub part.) I need user profile object ready before initializing anything else in angular (for fetching user role, login status etc.).
If I save only JWT on client side i need one extra ajax request before app load to get user info from JWT decode on server side, because token secret is on server (only after full page refresh). Token is valid or invalid, so handling errors in this case is much easier.
If I save JWT and user profile object as a string in storage on client side then this is rendundant and user can change manually that object and app can go down.
I prefer saving only JWT in storage on client side after successfully login, but i need some advice, how organize code in that case? How fetch user profile object after full page refresh?
Please help.
The most secure solution is to store the JWT in an HTTPS-Only cookie, then make a request of the server to get the user object.
If you want to avoid that extra call to the server you will need to get creative. One approach I'm trying is storing the claims body of the JWT on the client - just the body, the signature is excluded. With the signature excluded the "token" is no longer a JWT and cannot be used for authentication, thus preventing the actual access token from being stolen out of local storage.
However this DOES assume two things about the claims body:
1) That the information is opaque and does not contain personally identifiable information (PII) about the user (local storage is vulnerable to XSS attacks).
2) Your Angular application does not leak sensitive information to the user if this object is modified in local storage (you should not store sensitive information in your Angular application, it should be protected by an API)
3) As with all cookie-based authentication strategies, you are protecting yourself against CSRF Attacks
I work at Stormpath and I recently wrote a blog post on this very subject: Token Based Authentication for Single Page Apps.
Hope this helps!
For the sake of simplicity, I would store just JWT and implement an extra ajax call to fetch the user profile.
But if you absolutely want to avoid this one call, you may consider using asymmetrically signed JWT instead of encrypted JWT and then extract data on the client side, assuming you control the creation of JWT.

Facebook SDK / Where to store the long-lived access token?

I use the Facebook Javascript SDK logging in User by retrieving a short-lived access token.
This short-lived access token is immediately sent to my app server, in order to get a long-lived one from it.
I think about 2 ways to deal with this token:
Storing it as a User's field (User being an Entity dealing only with authentication mechanism, not the same as UserProfile) in the database, so that it can only be associated to its particular user.
Do not store it in the database but replace the Facebook cookie containing the initial short-lived access token by the long-lived one.
I guess the first way is handy, since I wouldn't need to care about any cookies at all.
What would be the common good practice?

Categories