Security and best practices for auth w/ refresh & access tokens

Viewed 542

Let's say I have a web application where I implemented Refresh Token & Access token JWTs authentication system using the following flow.

  1. User logins with username and password in body that is sent to /login REST API endpoint.
  • Endpoint creates a Refresh Token with expiry time of 1 month and stores the hashed Refresh Token in a Db corresponding to User ID.
  • Endpoint creates JWT Access Token with expiry time of 15 mins that is signed with server secret key and encodes User ID.
  • Endpoint responds with Refresh and Access Tokens with expiry times to client.
  • Client stores Refresh Token in localStorage and Access Token in memory.
  1. User accesses REST API endpoints that require authorization by setting the Access Token in HTTP headers.
  • Endpoint checks that Access Token JWT is signed by server secret key.
  • Endpoint checks that Access Token JWT is not expired.
  • If endpoints return unauthorized or if client checks Access Token is expired, get new Access Token JWT from /refresh endpoint then retry.
  1. The /refresh endpoint accepts a non-expired Refresh Token and returns an updated Access Token JWT.
  • If hashed value of Refresh Token exists in Db table, return associated User ID and generate new Access Token JWT signed by server. Also generate a new Refresh Token, remove old entry from Db, and insert new entry (Refresh Token Rotation).
  • If hashed value of Refresh Token does not exist in Db table, return unauthorized and user is logged out and asked to re-login (i.e step #1).
  • Response to client is updated Refresh Token and Access Token JWT.
  • Client stores Refresh Token in localStorage and Access Token JWT in memory like before.
  1. If Refresh Token is expired or does not exist, user is logged out and asked to re-login (i.e step #1).

My questions are:

  1. The Refresh Token is stored in localStorage and this is visible to the user using dev tools. Couldn't a malicious user just take this Refresh Token and pass it to /refresh to get a functional Access Token JWT? Then using the token they could make malicious requests. I don't see this mentioned anywhere? Should the Refresh Token not be stored in localStorage ?

And in general, related to this question, is this flow and implementation secure? Is this the best practices? What should be changed or improved?

  1. If the Refresh Token expiry is 1 month, and the user does not login for 1 month they will be auto logged out and need reauthenticated. Is there any way around this?

  2. Are there any libraries or frameworks for NodeJS that manage this for you? I couldn't find any. I was only able to see OAuth2 libraries for stuff like "Sign in with GitHub" or "Sign in with Google", etc.

1 Answers
Related