Edit this page | Blame

Fix Refresh Token

Tags

  • status: open
  • priority: high
  • assigned: fredm
  • type: feature-request, bug
  • keywords: gn-auth, token, refresh token, jwt

Description

The way we currently provide the refresh token is wrong, and complicated, and leads to subtle bugs in the clients.

The refresh tokens should be sent back together with the access token in the same response with the following important considerations:

  • The access token is sent back as the body of the response
  • The refresh token is sent back as a httpOnly cookie
  • The refresh token should be opaque to the client — if it is a JWT, encrypt it

Server-Side Changes

The following changes will be necessary at the generation of the access token:

  • Generate the refresh token (possibly in the `create_token_response()` function in `gn_auth.auth.authentication.oauth2.grants.JWTBearerGrant`). Put the user ID, and expiration in the refresh token. Expiration can be provided as part of initial request.
  • Encrypt the refresh token (maybe use the auth-server's public key for this)
  • Save refresh token to DB with link to access token ID perhaps?
  • Attach the token to the response as a httpOnly cookie

at the refreshing of the access token, we'll need to:

  • Fetch the refresh token from the cookies
  • Decrypt it
  • Compare the user ID in the refresh token with that in the access token provided
  • Verify refresh token has not expired
  • Check that the refresh token is not revoked (revocation will happen when user logs out, on manual sys-admin revocation)
  • Generate new access token
  • Do we attach the same refresh token or generate a new one?

#### Gotchas

Since there are multiple workers, you could get a flurry of refresh requests using the same refresh token. We might need to handle that — maybe save the refresh request to DB with the ID of the access token used and the new access token, and simply return the same new access token generated by the first successful refresh worker.

This actually kills 2 birds with the one stone:

  • The refresh completes successfully if the refresh token is not expired and the access token is valid
  • In case the access token and refresh token are somehow compromised, the system returns the same, possibly expired access token, rendering the compromise moot.

Client-Side Changes

  • Get the refresh token from the cookies rather than from the body
  • Maybe: make refreshing the access token unaware of threads/workers
(made with skribilo)