frasertweedale / hs-jose

Haskell JOSE and JWT library
http://hackage.haskell.org/package/jose
Apache License 2.0
122 stars 46 forks source link

How to retrieve kid and algorithm in a JWT before verifying? #64

Closed donatello closed 6 years ago

donatello commented 6 years ago

This is related to verifying tokens created by Google's Secure Token API.

The token generated by their service contains a "kid" header that identifies the public key at https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com to verify with.

How can I retrieve the headers from the token? An example would be great.

frasertweedale commented 6 years ago

@donatello there can be multiple "kid" headers in a JWS: 0 or 1 for each signature. But it looks like this a JWT application so there will be at most one. So I think you want something like:

firstOf (signatures . header . kid . _Just . param)
  :: (HasJWSHeader a, Foldable t) => JWT t p a -> Maybe String

Only problem is, that's for a plain JWS, but there's currently no (exported) way to get from a JWT to the underlying JWS object. I will add an optic for this.

frasertweedale commented 6 years ago

@donatello does the referenced commit fix things for you? The snippet in my earlier comment should work fine now.

Also note some work going on in a separate branch, that enhances the JWKStore (now called VerificationKeyStore) to allow for IO as well as access the headers and payload to help it choose/find/retrieve keys. Let me know if you have thoughts about that approach. Code here: https://github.com/frasertweedale/hs-jose/blob/jwkstore-effects/src/Crypto/JOSE/JWK/Store.hs#L62-L71

donatello commented 6 years ago

@frasertweedale Yes, this worked, thank you.

Google's service publishes the pubkeys as an JSON key-value mapping object with a kid of the pubkey as the key. In my application I am using that to lookup the pubkey and only attempt to verify with that. Will the behaviour be the same with VerificationKeyStore? I would appreciate some sample code as I am not too familiar with lenses.

frasertweedale commented 6 years ago

@donatello it's two paths to the same goal. The haddock example in Store.hs at the branch linked above shows how you can look up a key on the file system, based on the "iss" claim in the JWT Claims Set payload. For your use case, reading the "kid" from the JWS header (which is also available to the lookup routine), and retrieving they key from some URL is conceptually similar. I might write up another example but since the above code is working fine for you I'll merge it soon, then close this issue.

Note that the change won't actually be released for a while (it will go out in v0.8 and I have a few other things to implement for that release**), so you might have to use the version from Git until then.

** including constructing a JWK from an X.509 cert :)