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

Refactor KeyProvider to receive the "Key Id" #167

Merged
merged 6 commits into from
May 4, 2017
Merged

Conversation

lbalmaceda
Copy link
Contributor

@lbalmaceda lbalmaceda commented Apr 20, 2017

This PR introduces changes to better support Key Rotation.

Super classes

JWT no longer implements DecodedJWT. Users who find this breaking need to update the return type of JWT.decode() and JWT.require() ... verify() to DecodedJWT instead of JWT.

JWT parts

Before this PR the DecodedJWT instance just allowed to obtain the original version of the token and the signature (third part). Now 2 more methods were added: getHeader() and getPayload() which return the first and second part of the header as it is, with a Base64 encoding.

KeyProvider refactor

Now receives a "Key Id" when asked for the PublicKey, and also asks for a "Signing Key Id" that will be set in the header of the token in the signing process. If the "Key Id" is being set by the user using the withKeyId() in the JWTCreator class, the library won't overwrite it with the one defined in the KeyProvider implementation.
Users who doesn't use KeyProvider (i.e. instantiate the algorithm by passing just the keys) or return null in the getSigningKeyId() call will not be affected by this and the kid claim won't be automatically set.

Example usage:

final MyOwnJwkProvider jwkProvider = new MyOwnJwkProvider("{JWKS_FILE_HOST}");
final RSAPrivateKey privateKey = //Get the key instance
final String privateKeyId = //Create an Id for the above key

RSAKeyProvider keyProvider = new RSAKeyProvider() {
    @Override
    public RSAPublicKey getPublicKeyById(String kid) {
        //Value might be null if it wasn't defined in the Token's header
        Jwk jwk = jwkProvider.get(keyId);
        return (RSAPublicKey) jwk.getPublicKey();
    }

    @Override
    public RSAPrivateKey getPrivateKey() {
        return privateKey;
    }
    
    @Override
    public String getPrivateKeyId() {
        return privateKeyId;
    }
};
Algorithm algorithm = Algorithm.RSA256(keyProvider);
//Use the Algorithm to create and verify JWTs.

Algorithms

The Algorithm#verify method changed it's signature: Now it will verify a given DecodedJWT instance instead of the byte[] of signature and contents. This was needed to get the "Key Id" claim and request it's associated PublicKey to the KeyProvider. Although this is a breaking change, users shouldn't be using the Algorithm class directly as it's purpose is to be called internally by the library.

README.md Outdated

#### Using a KeyProvider:

By using a `KeyProvider` the library delegates the decision of which key to use in each case to the user. For the verification process, this means that the provider will be asked for a `PublicKey` with a given **Key Id** value. Your provider implementation should have the logic to fetch the right key, for example by parsing a JWKS file from a public domain like [auth0/jwks-rsa-java](https://github.com/auth0/jwks-rsa-java) does. For the signing process, this means that the provider will be asked for a `PrivateKey` and it's associated **Key Id**, so it can set it in the Token's header for future verification in the same way. Check the [IETF draft](https://tools.ietf.org/html/rfc7517) for more information on how to implement this.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By using a KeyProvider you can in runtime change either the key used to verify the token signature or to sign a new token for RSA or ECDSA algorithms. This is achieved by implementing either RSAKeyProvider or ECDSAKeyProvider methods:

  • getPublicKeyById(String kid): Its called during token signature verification and it should return the key used to verify the token. If key rotation is being used, e.g. JWK it can fetch the correct rotation key using the id. (Or just return the same key all the time).
  • getPrivateKey(): Its called during token signing and the key will be used to sign the JWT.
  • getPrivateKeyId(): Its called during token signing and it should return the id of the key that identifies the one returned by getPrivateKey()

README.md Outdated
};
Algorithm algorithm = Algorithm.RSA256(keyProvider);
//Use the Algorithm to create and verify JWTs.
```
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Below this we can add a note saying that they could use jwks-rsa-java to perform the jwk handling

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants