Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFC: Support for multiple key IDs #31

Closed
nigoroll opened this issue Jan 29, 2020 · 3 comments
Closed

RFC: Support for multiple key IDs #31

nigoroll opened this issue Jan 29, 2020 · 3 comments
Labels
enhancement New feature or request

Comments

@nigoroll
Copy link

Before starting any development work, I would like to ask for opinions/advise on the following feature idea:
Seamless changes to the signing key of a JWT, be it symmetrical or asymmetrical, requires a rollover procedure where consumers start to accept a new key before issuers create any tokens signed by it. While it would be possible to support such rollover with just a second key to try (usually called a transition secret or key), using JSON Web Key (JWK) IDs (kid) appears to be the cleaner solution:
a kid (key id) parameter imforms consumers about which (known) key to use for validating a token.

Notice that this is particularly relevant in scenarios where a single JWT/JWS is used by multiple applications which need to be coordinated for secret/key rollover.

While complete JSON Web Signature (JWS) support would include many more JOSE header values, I would suggest to only add

  • support for the kid paramter
  • support for multiple public keys / secrets to accept, identified by a kid
  • stick to a single public key / secret to use for issuing tokens, which also needs to be identified by a kid

Opinions?

@fitodic
Copy link
Collaborator

fitodic commented Jan 29, 2020

Thank you for bringing this up! I agree that this would be a valuable addition, and if you have the time for it, feel free to send a PR 👍

This library uses PyJWT which already has support for specifying additional headers, including the kid header.

As to the proposed additions:

support for the kid paramter

I assume the kid header would be an additional setting?

  • support for multiple public keys / secrets to accept, identified by a kid
  • stick to a single public key / secret to use for issuing tokens, which also needs to be identified by a kid

Just to be clear, you are saying that the library will use a single private/public key pair for issuing outbound JWTs signatures, but use multiple public keys for verification of the incoming JWTs' signatures, i.e. to simultaneously support the old and new public keys?

@nigoroll
Copy link
Author

support for the kid paramter

I assume the kid header would be an additional setting?

Yes, I would want to preserve the current implementation without any key ids.

Just to be clear, you are saying that the library will use a single private/public key pair for issuing outbound JWTs signatures, but use multiple public keys for verification of the incoming JWTs' signatures, i.e. to simultaneously support the old and new public keys?

Yes, that would be the idea.

Do we want to keep the issue open for some time in case anyone else has input? Other than that, I am fine with closing any time.

@fitodic
Copy link
Collaborator

fitodic commented Jan 29, 2020

Do we want to keep the issue open for some time in case anyone else has input? Other than that, I am fine with closing any time.

I'm fine either way. 🙂

We can keep it open until a PR that implements it comes along.

@fitodic fitodic added enhancement New feature or request good first issue Good for newcomers and removed good first issue Good for newcomers labels Jan 29, 2020
nigoroll added a commit to nigoroll/django-rest-framework-jwt that referenced this issue Feb 15, 2020
The previous commit added support for multiple keys, which (despite
being useful as a fallback, if anything) implies multiple verification
attempts and thus is not computationally efficient.

We now support identifing keys by key id ("kid" header): When a JWT
carries a key id, we can identify immediately if it is known and only
need to make at most one verification attempt.

To configure keys with ids, JWT_SECRET_KEY, JWT_PRIVATE_KEY and
JWT_PUBLIC_KEY can now also be a dict in the form

	{ "kid1": key1, "kid2": key2, ... }

Closes Styria-Digital#31
nigoroll added a commit to nigoroll/django-rest-framework-jwt that referenced this issue Feb 15, 2020
The previous commit added support for multiple keys, which (despite
being useful as a fallback, if anything) implies multiple verification
attempts and thus is not computationally efficient.

We now support identifing keys by key id ("kid" header): When a JWT
carries a key id, we can identify immediately if it is known and only
need to make at most one verification attempt.

To configure keys with ids, JWT_SECRET_KEY, JWT_PRIVATE_KEY and
JWT_PUBLIC_KEY can now also be a dict in the form

	{ "kid1": key1, "kid2": key2, ... }

Closes Styria-Digital#31
nigoroll added a commit to nigoroll/django-rest-framework-jwt that referenced this issue Feb 16, 2020
The previous commit added support for multiple keys, which (despite
being useful as a fallback, if anything) implies multiple verification
attempts and thus is not computationally efficient.

We now support identifing keys by key id ("kid" header): When a JWT
carries a key id, we can identify immediately if it is known and only
need to make at most one verification attempt.

To configure keys with ids, JWT_SECRET_KEY, JWT_PRIVATE_KEY and
JWT_PUBLIC_KEY can now also be a dict in the form

	{ "kid1": key1, "kid2": key2, ... }

Closes Styria-Digital#31
nigoroll added a commit to nigoroll/django-rest-framework-jwt that referenced this issue Feb 16, 2020
The previous commit added support for multiple keys, which (despite
being useful as a fallback, if anything) implies multiple verification
attempts and thus is not computationally efficient.

We now support identifing keys by key id ("kid" header): When a JWT
carries a key id, we can identify immediately if it is known and only
need to make at most one verification attempt.

To configure keys with ids, JWT_SECRET_KEY, JWT_PRIVATE_KEY and
JWT_PUBLIC_KEY can now also be a dict in the form

	{ "kid1": key1, "kid2": key2, ... }

Closes Styria-Digital#31
nigoroll added a commit to nigoroll/django-rest-framework-jwt that referenced this issue Feb 18, 2020
The previous commit added support for multiple keys, which (despite
being useful as a fallback, if anything) implies multiple verification
attempts and thus is not computationally efficient.

We now support identifing keys by key id ("kid" header): When a JWT
carries a key id, we can identify immediately if it is known and only
need to make at most one verification attempt.

To configure keys with ids, JWT_SECRET_KEY, JWT_PRIVATE_KEY and
JWT_PUBLIC_KEY can now also be a dict in the form

	{ "kid1": key1, "kid2": key2, ... }

Closes Styria-Digital#31
nigoroll added a commit to nigoroll/django-rest-framework-jwt that referenced this issue Mar 5, 2020
The previous commit added support for multiple keys, which (despite
being useful as a fallback, if anything) implies multiple verification
attempts and thus is not computationally efficient.

We now support identifing keys by key id ("kid" header): When a JWT
carries a key id, we can identify immediately if it is known and only
need to make at most one verification attempt.

To configure keys with ids, JWT_SECRET_KEY, JWT_PRIVATE_KEY and
JWT_PUBLIC_KEY can now also be a dict in the form

	{ "kid1": key1, "kid2": key2, ... }

When a JWT does not carry a key id ("kid" header), the default is to
fall back to trying all keys if keys are named (defined as a dict).
Setting JWT_INSIST_ON_KID: True avoids this fallback and requires any
JWT to be validated to carry a key id _if_ key IDs are used

Closes Styria-Digital#31
nigoroll added a commit to nigoroll/django-rest-framework-jwt that referenced this issue Mar 7, 2020
The previous commit added support for multiple keys, which (despite
being useful as a fallback, if anything) implies multiple verification
attempts and thus is not computationally efficient.

We now support identifing keys by key id ("kid" header): When a JWT
carries a key id, we can identify immediately if it is known and only
need to make at most one verification attempt.

To configure keys with ids, JWT_SECRET_KEY, JWT_PRIVATE_KEY and
JWT_PUBLIC_KEY can now also be a dict in the form

	{ "kid1": key1, "kid2": key2, ... }

When a JWT does not carry a key id ("kid" header), the default is to
fall back to trying all keys if keys are named (defined as a dict).
Setting JWT_INSIST_ON_KID: True avoids this fallback and requires any
JWT to be validated to carry a key id _if_ key IDs are used

Closes Styria-Digital#31
nigoroll added a commit to nigoroll/django-rest-framework-jwt that referenced this issue Apr 20, 2020
The previous commit added support for multiple keys, which (despite
being useful as a fallback, if anything) implies multiple verification
attempts and thus is not computationally efficient.

We now support identifing keys by key id ("kid" header): When a JWT
carries a key id, we can identify immediately if it is known and only
need to make at most one verification attempt.

To configure keys with ids, JWT_SECRET_KEY, JWT_PRIVATE_KEY and
JWT_PUBLIC_KEY can now also be a dict in the form

	{ "kid1": key1, "kid2": key2, ... }

When a JWT does not carry a key id ("kid" header), the default is to
fall back to trying all keys if keys are named (defined as a dict).
Setting JWT_INSIST_ON_KID: True avoids this fallback and requires any
JWT to be validated to carry a key id _if_ key IDs are used

Closes Styria-Digital#31
nigoroll added a commit to nigoroll/django-rest-framework-jwt that referenced this issue Apr 23, 2020
The previous commit added support for multiple keys, which (despite
being useful as a fallback, if anything) implies multiple verification
attempts and thus is not computationally efficient.

We now support identifing keys by key id ("kid" header): When a JWT
carries a key id, we can identify immediately if it is known and only
need to make at most one verification attempt.

To configure keys with ids, JWT_SECRET_KEY, JWT_PRIVATE_KEY and
JWT_PUBLIC_KEY can now also be a dict in the form

	{ "kid1": key1, "kid2": key2, ... }

When a JWT does not carry a key id ("kid" header), the default is to
fall back to trying all keys if keys are named (defined as a dict).
Setting JWT_INSIST_ON_KID: True avoids this fallback and requires any
JWT to be validated to carry a key id _if_ key IDs are used

Closes Styria-Digital#31
nigoroll added a commit to nigoroll/django-rest-framework-jwt that referenced this issue Apr 23, 2020
The previous commit added support for multiple keys, which (despite
being useful as a fallback, if anything) implies multiple verification
attempts and thus is not computationally efficient.

We now support identifing keys by key id ("kid" header): When a JWT
carries a key id, we can identify immediately if it is known and only
need to make at most one verification attempt.

To configure keys with ids, JWT_SECRET_KEY, JWT_PRIVATE_KEY and
JWT_PUBLIC_KEY can now also be a dict in the form

	{ "kid1": key1, "kid2": key2, ... }

When a JWT does not carry a key id ("kid" header), the default is to
fall back to trying all keys if keys are named (defined as a dict).
Setting JWT_INSIST_ON_KID: True avoids this fallback and requires any
JWT to be validated to carry a key id _if_ key IDs are used

Closes Styria-Digital#31
nigoroll added a commit to nigoroll/django-rest-framework-jwt that referenced this issue Apr 23, 2020
The previous commit added support for multiple keys, which (despite
being useful as a fallback, if anything) implies multiple verification
attempts and thus is not computationally efficient.

We now support identifing keys by key id ("kid" header): When a JWT
carries a key id, we can identify immediately if it is known and only
need to make at most one verification attempt.

To configure keys with ids, JWT_SECRET_KEY, JWT_PRIVATE_KEY and
JWT_PUBLIC_KEY can now also be a dict in the form

	{ "kid1": key1, "kid2": key2, ... }

When a JWT does not carry a key id ("kid" header), the default is to
fall back to trying all keys if keys are named (defined as a dict).
Setting JWT_INSIST_ON_KID: True avoids this fallback and requires any
JWT to be validated to carry a key id _if_ key IDs are used

Closes Styria-Digital#31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants