MicahParks/keyfunc

Error validating Azure JWT

ArnoSen opened this issue · 5 comments

Hi,

I am running into an issue where parsing / validating of an Azure JWT fails with error "token signature is invalid: crypto/rsa: verification error".

The code I use is straightforward:

   jwks, err := keyfunc.Get("https://login.microsoftonline.com/common/discovery/v2.0/keys", keyfunc.Options{}) // See recommended options in the examples directory.
                                if err != nil {
                                        panic(err)
                                }
   token, err := jwt.Parse(tokenString, jwks.Keyfunc)
   if err != nil {
      panic(err)
   }

I verified the Modulus and Exponent with my own implementation and it looks fine. When comparing that with the cert in x5c, the public cert looks correct. Also I tried a different jwk link that references the tenant id (https://login.microsoftonline.com/{tennant id}/discovery/keys) and it returns the same public cert.
The jwt decodes itself decodes fine. It is just that the rsa verification fails.
When reading through all the issue including closed ones, I did not get any new ideas for things I could try.
I am out of options other than a good night sleep and see what I find tomorrow. But any help would be appreciated.

If you could provide me the public keys in the JWK Set and a JWT that does not contain any secrets, that would be most helpful for reproducing this.

Thank you for opening this issue, @ArnoSen. I was able to reproduce the token signature is invalid: crypto/rsa: verification error with the JWK Set and JWT you sent privately. It looks to me like this error is correct.

The failure occurs on this line during signature verification.

Since the JWK from the JWK Set with the key ID the JWT claims to be signed by is a standard RSA 2048 bit key, it's unlikely a parsing error by the keyfunc package. This could be do to JWT forging, or more likely, a configuration mistake. I would assume a configuration mistake would not result in this error, because the JWK key ID appears to be random and a conflicting name in another environment should be impossible. Another possibility is the JWT system being used is non-standard. See that last option explored below.

I see that there is a JSON attribute in the JWT header called "nonce". I've never seen this before and it looks important to me. Perhaps you could be running into a scenario where this is a non-standard JWT? It looks like Azure Active Directory has some funny business when it comes to validating JWTs. It seems there is a configuration change you may be able to make to get normal JWTs, see the links below.

Relevant links:

It seems to me the the Azure ecosystem performs some non-standard JWT signing and verification. Unfortunately, this does not seem to be documented anywhere, so I would recommend configuring Azure products to use standardized methods of JWT signing and verification to be interoperable with open source projects like this one.

If you do find some configuration that allows your Azure products to operate using keyfunc, please do leave a comment with details on the actions you've performed. I assume others have run into similar issues.

@MicahParks thanks a lot for your help.

The issue is actually the same as #41.

For those running into the same issue, I recommend reading the thread referenced above The Github Issue.

A short summary of the thread is:

  • if the token you get back has a 'nonce' header, it tells you it is not a real JWT although the format is like a JWT. It should be considered an opaque token.
  • in case there is a nonce, local validation is impossible because the nonce is a SHA2 of a opaque string. This string is needed to reconstruct the original jwt. Since SHA2 is a hash / one-way encryption, this is not possible.
  • the token can be verified by the service that matches the audience. I assume this will be MS Graph (or a related MS service)
  • you should be able to validate the token when the request for a token contains an application specific scope. See #41 (comment).

When I have implemented the functionality I will verify and update above information.

I'm going to close since the source of the issue was discovered and there hasn't be any discussion lately. Please feel free to keep commenting on this issue if there are details to document for others.

I ran into the same issue today and wanted to give an update, specifically on the below statement:

you should be able to validate the token when the request for a token contains an application specific scope. See #41 (comment).

The problem can be solved without creating any application specific scope. It's sufficient to request the .default scope in form of the so called "GUID based app identifier", which is built like: {CLIENT-ID}/.default

For example (random UUID):
6ad6f498-a681-4c9f-b55c-ffef284303ab/.default