Google OpenID Connect can't locate which key to use

Issue #138 resolved
Stuart Watt created an issue

I'm not completely convinced I have identified this problem, but there's a more detailed explanation here: http://stackoverflow.com/questions/30342783/intermittant-bad-jws-signature-w-t-google-apps-open-id-authentication/31524820#31524820

Summary:

The main challenge with Google is that it seems to provide two alternate keys from its certificates endpoint. These have the same algorithm, but different key identifiers. Unfortunately, the default implementation of the Connect2D JWT decoder selects a key by algorithm alone (i.e., just the RS256), so it is down to luck which one you get first.

This means the key id (kid) is ignored, even though it is present in the JWT header. In effect, the verifier selected is 50% likely to be the wrong one, and therefore obviously won't verify. All lookups are sequential, so probably stable, leading the observed behaviour of periods of consistent success or failure.

A correct implementation of the JWT decoder should probably:

  • Use the kid as well as the algorithm to select which key to use
  • If no verifier is available for a given kid, should probably re-fetch the keys from the discovery API endpoint. This is because Google change their keys pretty often anyway, so if you initialize once you'll never get the new keys.

Comments (8)

  1. Stuart Watt reporter

    Relevant spec sections for reference:

    http://openid.net/specs/openid-connect-core-1_0.html#Signing

    When using RSA or ECDSA Signatures, the alg Header Parameter value of the JOSE Header MUST be set to an appropriate algorithm as defined in JSON Web Algorithms [JWA]. The private key used to sign the content MUST be associated with a public key used for signature verification published by the sender in its JWK Set document. If there are multiple keys in the referenced JWK Set document, a kid value MUST be provided in the JOSE Header. The key usage of the respective keys MUST support signing.

    ...

    Rotation of signing keys can be accomplished with the following approach. The signer publishes its keys in a JWK Set at its jwks_uri location and includes the kid of the signing key in the JOSE Header of each message to indicate to the verifier which key is to be used to validate the signature. Keys can be rolled over by periodically adding new keys to the JWK Set at the jwks_uri location. The signer can begin using a new key at its discretion and signals the change to the verifier using the kid value. The verifier knows to go back to the jwks_uri location to re-retrieve the keys when it sees an unfamiliar kid value. The JWK Set document at the jwks_uri SHOULD retain recently decommissioned signing keys for a reasonable period of time to facilitate a smooth transition.

  2. Connect2id OSS

    Hi Stuart,

    Which version of the library are you using?

    The 4.0 release candidates include a new framework for key selection which should be able to handle multiple key IDs.

  3. Stuart Watt reporter

    I'm using 3.4.1 -- this is a dependency from pac4j. However, I've had a look at the sources, and I can't see where in the DefaultJWTDecoder the key identifiers are used to select the appropriate verifier. In theory the verifier itself might handle multiple keys, but that'd be in the JOSE component not here.

    There are API differences too, I've come across one already in AuthorizationCodeGrant which means I'll need to work around that at least to upgrade.

    Maybe if you could point me at this new framework, or even better an example of its use, I could have a go at working it through. I'm already patching the hell out of pac4j because it couldn't provide absolute URLs properly.

  4. Connect2id OSS

    Hi Stuart,

    Sorry, there was a bit of a mix up, it is the Nimbus JOSE+JWT lib that now has a brand new framework for processing JWTs (http://connect2id.com/blog/nimbus-jose-jwt-4.0-rc1), however, its integration into the OIDC SDK is still on our to do list. We're currently busy completing a new release of the Connect2id server, and will not be able to dedicate time on the SDK until 29 July.

    If you're using v3.4.1 of the OIDC SDK you have two options:

    1. Implement an alternative JWTDecoder.

    2. Extend the JWSVerifier implementation to support key ID lookup.

    The first approach will probably be the easier of the two.

  5. Stuart Watt reporter

    That's fine -- and I've already started doing that (option 1). I'm not expecting much effort from anyone else on this, but since there are a number of sporadic reports of the JWS signature verification failing, especially for Google OIDC, I thought it a good idea to have some public issues around that could mark the causes of the problem.

  6. Phil Laird

    Hi,

    I think I have run into this issue and was wondering if it has been resolved and I am implementing the decoding process wrong or if it will be resolved in the 5.0 release.

    Regards

  7. Log in to comment