Replies: 5 comments 1 reply
-
One thing that this module does is to follow the structure that is defined in the RFCs. You may already know this, but I'm going to explain just for completeness: By definition JWT is a piece of raw data, with some fields that describe for whom the data is for ( JWS wraps this to provide the guarantee that the the message has not been tampered with by adding a signature. Its contents do not necessarily need to be a JWT, it can be anything. However, in the wild when you receive a JWT, it's almost always a JWT object wrapped in JWS. This is why often times libraries seem to provide an API that takes this assumption and thus the API assumes JWS=JWT, restricting further flexibility when it comes to a more general case. Now, given that logic, So, how do you get to the JWS parts? The same way as JWT: use // untested, pulled out of my memory
msg, _ := jws.Parse( base64_or_json_formatted_jws )
// While JWT enveloped with JWS in compact format only has 1 signature,
// a generic JWS message may have multiple signatures. That is why
// you need to go through `Signatures()`
kid := msg.Signatures()[0].ProtectedHeaders().KeyID() The part that I like about my library is that this is symmetrical throughout this module: If you want to do the same thing with JWE, you just do However, that's a lot of boilerplate code. From here on I'm just guessing, but are you using the If that's the case you should just provide a I hope I guessed your use-case correctly, but otherwise wrt to your "Request: Could it be made a little easier to access JWT header fields?" I would have to know the context in which you want to do this. |
Beta Was this translation helpful? Give feedback.
-
Here's some doc that paraphrases what I wrote in my earlier message: https://github.com/lestrrat-go/jwx/blob/develop/v2/docs/02-jws.md#parse-a-jws-message-and-access-jws-headers |
Beta Was this translation helpful? Give feedback.
-
This is a great answer! Thank you. The jump from You're also right that I am using the Here's what I came up with. I specify a If this looks good to you, maybe it can help others who ask a similar question. // KeyFetcher allows other parts of your code to implement a simple key lookup.
// Pair with jwk.FromRaw or similar for returning results.
type KeyFetcher func(c context.Context, keyID string) (jwk.Key, error)
// KeyHandler wraps a KeyFetcher to implement jws.KeyProvider.
// This is used in tandem with jwt.Parse to provide dynamic key lookup.
//
// In a more complex system, you might add logging, metrics, caching, rate limiting...
type KeyHandler struct {
Fetcher KeyFetcher
}
func (h *KeyHandler) FetchKeys(c context.Context, result jws.KeySink, sig *jws.Signature, msg *jws.Message) error {
// Extract whatever you need from jws.Headers
alg := sig.ProtectedHeaders().Algorithm()
kid := sig.ProtectedHeaders().KeyID()
// Run the dynamic key lookup
key, err := h.Fetcher(c, kid)
if err != nil {
return err
}
// Check that the fetched key is marked with the correct key ID
fetched_kid := key.KeyID()
if kid != fetched_kid {
return fmt.Errorf("Fetching kid '%s' returned different kid '%s'", kid, fetched_kid)
}
// Mark as parse candidate
result.Key(alg, key)
return nil
}
// Trivial usage
func Parse(c context.Context, jwtRaw []byte, handler *KeyHandler) (jwt.Token, error) {
// From jwt.WithContext docs: soon a context will be part of the function signature
// May as well take a context now to be ready for the API change
return jwt.Parse(jwtRaw, jwt.WithKeyProvider(handler), jwt.WithContext(c))
} |
Beta Was this translation helpful? Give feedback.
-
Yeah, looks about right. nit, but if you don't need to handle the case where KeyID is not available in the |
Beta Was this translation helpful? Give feedback.
-
Good point, edited. Thanks again for your help. |
Beta Was this translation helpful? Give feedback.
-
Hello!
Excellent library. This is both a question and a feature request :)
I am working with a system that will have a large number of keys, and so not a good use case for
jwt.WithKeySet
. Instead, it would be best to check thekid
in the header, fetch that key from another system, then validate.I thought that it would be easy to do this with
jwt.ParseInsecure
, but I notice thatjwt.Token
has no access to header fields:So I had a look at those methods, but did not see an easy way to access the parsed header fields, instead they appear to mainly work with the base64 encoded portions of the message.
So:
Question: How should I do that with this library?
Request: Could it be made a little easier to access JWT header fields? For example, with a different library:
Beta Was this translation helpful? Give feedback.
All reactions