7

This is not a coding question, but a conceptual question for the correct handling and processing of a refresh token.

I have a single page app which issues a jwt token when logging in. The token works just fine. Now, I want to set the expiration to a low value, and use a refresh token to refresh the bearer token.

The question is, what claims should be stored in the refresh token? And what steps are supposed to be done to validate the refresh token before issuing a new token?

For example, right now my refresh token is a jwt which stores an expiration, so the client knows when the refresh token expires, and a username claim so that I know what user the refresh token is associated with.

So then when the refresh token is recieved:

  1. Check that it is not expired.
  2. Check that it has not been revoked.
  3. Use the UserName in the refresh token to issue a new short-lived bearer token.

Is this the correct workflow for this? I just want to make sure I am not missing any security checks.

Greg Gum
  • 33,478
  • 39
  • 162
  • 233

1 Answers1

2

If your application is a single page application, you should not use long lived refresh tokens as you have no way of securely storing them.

OAuth2 defines a number of grant flows for different types of clients (which I've described here). Refresh tokens are only meant for confidential clients (like web applications living on a secured server).

Your refresh token is just as vulnerable to theft as your access token, since both are bearer tokens stored on the client.

Some OAuth libraries allow SPA or other non-confidential clients to get a new access token by talking to the token endpoint of the authorization server using a session token in a cookie. As long as the cookie is valid, the user can get a new access token. After that, the user will need to re-authenticate. Of course cookies can be marked secure and http only, making them harder to steal.

If you issue the JWT tokens from the same service endpoint that consumes the access tokens, you could have the client include a nonce in the token request that you hash and include as a claim in the token. The client can send the JWT in the Authorization header and the nonce in a custom header. Your token verification would hash the nonce again and compare it to the claim in the JWT. That way, if your token is stolen is harder to use without the nonce value. Of course, in a targeted attack, your nonce could also be stolen.

Community
  • 1
  • 1
MvdD
  • 22,082
  • 8
  • 65
  • 93
  • It's true that localStorage can be stolen from injected javascript, but the same can be said for cookies, so I don't know that cookies are any better. Local Storage from https is only available from other https, so it's also just as secure in that wise as well. We do of course use https and we also associate an IP with a refresh token. So if the IP changes, the token is invalidated. So even if the refresh token is stolen, it is not usable from a different IP. While even that can be spoofed, the security factor is about as high as you can get without turning to dual auth. – Greg Gum May 27 '18 at 02:31
  • The first line of your comment is not true. HttpOnly cookies cannot be stolen via XSS (see https://www.owasp.org/index.php/HttpOnly). Any cookies set by the server should be made HttpOnly and HTTPS only (secure). – MvdD May 27 '18 at 02:41
  • Ok, I read the article on httpOnly and I agree with you. But how to include an httponly cookie when using ajax? – Greg Gum May 27 '18 at 03:01
  • In the JWT libraries I mentioned, the authorization server sets the cookie after the user authenticated. The AJAX app can come back to refresh the JWT while the cookie is valid. Any request to the authorization server will automatically include the cookie, but the JavaScript in the SPA cannot access the cookie (and therefore not lose it). – MvdD May 27 '18 at 03:32
  • Sounds like a good idea to me. To Recap: Use localStore for the token, but then look for a httpOnly/Secure cookie along with the request and use it to validate the bearer token. Do I understand this correctly? – Greg Gum May 27 '18 at 15:29
  • 1
    When issuing the JWT token, also set a httpOnly and secure cookie. Use the JWT token from localStorage. When refreshing the JWT token, validate the info in the cookie. – MvdD May 27 '18 at 17:03