auth0 / express-jwt

connect/express middleware that validates a JsonWebToken (JWT) and set the req.user with the attributes
MIT License
4.49k stars 444 forks source link

I'd like to be able to provide multiple valid secrets for a given request, preferably dynamically as well #310

Closed dead-claudia closed 1 year ago

dead-claudia commented 1 year ago

Please do not report security vulnerabilities here. The Responsible Disclosure Program details the procedure for disclosing security issues.

Thank you in advance for helping us to improve this library! Your attention to detail here is greatly appreciated and will help us respond as quickly as possible. For general support or usage questions, use the Auth0 Community or Auth0 Support. Finally, to avoid duplicates, please search existing Issues before submitting one here.

By submitting an Issue to this repository, you agree to the terms within the Auth0 Code of Conduct.

Describe the problem you'd like to have solved

I'm looking for a way to migrate from one key to another without rejecting existing keys, to allow for short-lived secrets without disrupting users too much.

Describe the ideal solution

The easiest way to do this is to just have a period where you accept multiple secrets. The process would look something like this:

  1. Add key to list of accepted keys for both the issuer and consumer servers
  2. Update key issuer to use new key for issuing keys
  3. Wait for token lifespan plus a few minutes or so to account for clock differences
  4. Remove key from list of accepted keys for both the issuer and consumer servers

The API could just accept arrays of jwt.Secrets anywhere that type is accepted within this immediate module and offload the rest of that complexity to the callee.

Alternatives and current work-arounds

  1. Bite the bullet and just let every token fail to check.
  2. Fork this module. This is obviously far from ideal.

Additional context

Add any other context or screenshots about the feature request here.

jfromaniello commented 1 year ago

This is a very common case, for which the secret parameter accepts either a secret or a GetVerificationKey callback.

https://github.com/auth0/express-jwt#retrieve-key-dynamically

Ideally you will have a map of KIDs (key-ids to secrets) and then use the kid header as follows:

var getSecret = async function (req, token) {
  const { kid } = token.header;
  return secrets[kid];
};

Notice is an async function so you could store this on a database etc.

At some point your api will stop accepting jwts signed with the old key.

dead-claudia commented 1 year ago

Thanks! I have no idea why I didn't think of that.

It might be worth calling out in the README in that section as well as an example so others can see how it'd be done.

jfromaniello commented 1 year ago

Good call, thank you. I added an example in the readme