JWT Expiration Handling and JWT Payload Update

I have a Koa-based Node.js core server for my personal / hobby application.

I implemented session processing using JWT tokens. The client (AngularJS) receives the token after a successful login and stores the token somewhere (currently in sessionStorage , but this does not matter for the purpose of this question).

I have two questions:

  • When I need to update the user record that the JWT represents, let's say the user has enabled 2FA, so I asked him to provide his phone number, and I would like to set that phone number in the user record. Currently, after successfully checking the phone number, I call my server to update the user record and I create a new JWT token with the updated user record (I exclude confidential information from the JWT token as a hashed password, but I would like to specify the phone number to use on the client side). Is it possible to create a new token when some credentials change and update an existing client-side token with this new token? Do I ever have to create another token, only to create one and only with successful authentication? How can I then update the token payload?

  • How should I handle expired JWT tokens? In my opinion, I have 3 (possible) scenarios:

    2.1. JWT is set up for a short lifetime, say 15 minutes. If the backend server responds with 401 Unauthenticated 'Invalid token' (I think this is the default behavior of koa-jwt ), then I automatically exit my client and require re-authentication. But I also created additional middleware, which is the last in the chain on the backend, to recreate the token with an updated expiration date, and the client will also replace the existing token with the updated one. Therefore, if the user is active and uses the application for each protected API call, if successful, he will create a new token to replace the old token.

    2.2. JWT is set to lasting, say, 1 week, and if it expires, I refuse to re-authenticate from the client.

    2.3. Copy https://tools.ietf.org/html/rfc6749#section-1.5 . Here, when creating the JWT token after successful authentication, we send access_token, as well as refresh_token. When the access_token has expired and the server responds with HTTP 401 "invalid token" ( koa-jwt by default), the client sends a refresh_token to the backup to require a new access_token (and possibly a new refresh_token). In this case, I do not quite understand how refresh_token is checked against the old access_token in order to provide a new token? Or why should we have a refresh_token?

Useful tips on common topics (JWT updates and JWT validity).

+7
javascript koa jwt
source share
2 answers

Starting from the bottom, I would ignore update tokens, since I don't think they will help you. They tend to target other scenarios in which a client application can provide more secure storage than a user browser — I think native mobile applications or server-side web applications.

Update tokens are durable . This means that when a client receives one server, this token must be securely stored so that it is not used by potential attackers, for this reason it is not safe to store them in a browser.

(emphasis mine source update tokens )

This means that option 2.3 is basically the same as 2.2, which is not a bad option. It is not uncommon to have web applications with a long session duration. If your application is not very sensitive, it is recommended to use a long session to improve the user experience. For example, Django uses a default of two weeks for the age of its cookie session. See SESSION_COOKIE_AGE .

The remaining option (2.1) is usually called a rolling session. The session timeout is short, but as long as the user continues to use the application during this interval, the session is automatically updated. Perhaps this is the most common approach, or at least the one that I have used most of the time, so I am biased. The only thing I would like to point out is that a rolling session is usually implemented with opaque session identifiers stored on the client side as cookies, and then with the actual session data stored on the server.

Your approach is slightly different since you have a stateless JWT token (it contains the actual user data) stored in the local storage of the browser. As you said, in order to update a token, you will have to generate a new one because you will need to generate a new signature.

The signature is used to verify that the sender of the JWT is the one who says it is , and to ensure that the message has not been changed in transit.

(emphasis mine, source of JSON tokens )

Having said all this, I would consider the following:

  • Ask yourself if you really need JWT, or if regular session identifiers stored as cookies ( HTTP only ) will simplify your logic.
  • If the JWT is a requirement, for example, you have another API that will also accept these tokens as authentication, then I would consider option 2.1 or 2.2, since update tokens are not recommended for a browser-based application.

Having said that, you should also bear in mind that JWTs are not huge, but they will still be overhead if you decide to automatically renew. You can mitigate this a bit by choosing a session duration of 20 minutes and do an automatic update after half the session.

Another point is that a vulnerability, such as XSS in your application, will output an access token to an attacker, since the entered scripts can be read from localStorage / sessionStorage , this could be another point in favor of only HTTP session cookie storage.

+5
source share

I would like to answer your second question before I can move on to the first.

Basically, the third option you mentioned is the best way to update access tokens. The access token should be short lived (~ 5 minutes), and the update token should be longer. When your access token expires, send the update token to the backend and get a new access token. So your answer should be something like this:

 { "token_type":"bearer", "access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiVlx1MDAxNcKbwoNUwoonbFPCu8KhwrYiLCJpYXQiOjE0NDQyNjI4NjYsImV4cCI6MTQ0NDI2Mjg4Nn0.Dww7TC-d0teDAgsmKHw7bhF2THNichsE6rVJq9xu_2s", "expires_in":10, "refresh_token":"7fd15938c823cf58e78019bea2af142f9449696b" } ", { "token_type":"bearer", "access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiVlx1MDAxNcKbwoNUwoonbFPCu8KhwrYiLCJpYXQiOjE0NDQyNjI4NjYsImV4cCI6MTQ0NDI2Mjg4Nn0.Dww7TC-d0teDAgsmKHw7bhF2THNichsE6rVJq9xu_2s", "expires_in":10, "refresh_token":"7fd15938c823cf58e78019bea2af142f9449696b" } 

So, the idea is to separate your application from the authorization server (which generates the access / update token) and the resource server (check the access token and gain access to resources). You can save the scheme for checking the update token with the access token on the authorization server. Please refer to the section of the circuit mentioned in this link which may give you some idea. Oauth2 . You can change the circuit to suit your needs. You do not need to send an update token along with an access token for each request call. Update the token can only be sent to the authorization server to create a new access token. How to create update tokens? If I use Java, I would use UUID.randomUUID() to create a unique update token.

Now, to answer your first question, if you want to update your JWT payload based on your updated user records, you can use the same update token to create a new access token with an updated payload. The logic remains the same, because if the phone number exists in the user record, it is added to the payload, and if not, it will be zero in the payload.

The main advantage of using the Refresh token is that access tokens can be updated at any time using update tokens.

+3
source share

All Articles