When working with OAuth and Open ID Connect, there are times when you’ll want to inspect the contents of id, access or refresh tokens. The website https://jwt.io is useful as you can drop in the token in the pane on the left, and the site dynamically decodes the header, body and signature for the JWT.
Unfortunately by itself the signature on the JWT can’t be verified as the website doesn’t know what key to use to validate the signature. The header of the JWT does provide information about the algorithm used (ie RS256) and the id of the key used but this by itself isn’t enough to locate the key to be used.
As RS256 is a public/private key algorithm, there is a private key, which the issuer holds, and a public key which is available to anyone to access. The former is used to generate the signature for a JWT; the later can then be used to validate the signature. To find the public key to use to validate the signature I’ll start with the OpenID Connect configuration document, which is available for any tenant at:
https://login.microsoftonline.com/{tenantId}/.well-known/openid-configuration
eg https://login.microsoftonline.com/nicksdemodir.onmicrosoft.com/.well-known/openid-configuration
The returned configuration document contains an attribute, jwks_uri, which points at https://login.microsoftonline.com/common/discovery/keys
Loading the jwks_uri returns another JSON document which lists a number of keys. Now we can use the kid from the header of the JWT to identify which key to use, in this case the first key in the list.
Attempting to simply copy the x5c value from the list of keys into the Public Key or Certificate box on the jwt.io website will still not verify the signature of the JWT. In order to verify the signature, wrap the key in BEGIN and END CERTIFICATE markers as follows:
—–BEGIN CERTIFICATE—–
MIIDBTCCAe2gAwIBAgIQEsuEXXy6BbJCK3bMU6GZ/TANBgkqhkiG9w0BAQsFADAtMSswKQYDVQQDEyJhY2NvdW50cy5hY2Nlc3Njb250cm9sLndpbmRvd3MubmV0MB4XDTE2MTEyNjAwMDAwMFoXDTE4MTEyNzAwMDAwMFowLTErMCkGA1UEAxMiYWNjb3VudHMuYWNjZXNzY29udHJvbC53aW5kb3dzLm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKd6Sq5aJ/zYB8AbWpQWNn+zcnadhcMYezFvPm85NH4VQohTm+FMo3IIJl6JASPSK13m9er3jgPXZuDkdrEDHsF+QMEvqmffS2wHh3tKzasw4U0jRTYB0HSCbmnw9HpUnv/UJ0X/athO2GRmL+KA2eSGmb4+5oOQCQ+qbaRXic/RkAOLIw1z63kRneLwduQMsFNJ8FZbWkQFj3TtF5SL13P2s/0PnrqwGD59zcbDu9oHOtciu0h++YhF5CWdWEIgafcZk9m+8eY12BKamvPdBnyfpz6GVTenJQe2M+AGz5RSNshvI976VUbBiaIeNzvzaG91m62kFWLRqE3igq6D02ECAwEAAaMhMB8wHQYDVR0OBBYEFAgoZ9HLgFxH2VFGP6PGc4nFizD2MA0GCSqGSIb3DQEBCwUAA4IBAQBSFXalwSJP/jihg04oJUMV2MTbuWtuFhdrdXiIye+UNc/RX02Q9rxd46BfGeKEBflUgNfEHgyEiWTSLAOSDK70vu+ceCVQCGIQPjnGyYOpm80qAj/DNWZujVcSTTV3KZjMFsBVP7miQowfJQ58u9h8yuJHNhPpB2vOFmNhm4uZq3ve529Xt51HdtQGG9+Z9n1DhObqzkbz8xEFjA+KdfcRsZXa14ZkpAOe35VgyY0f8x34Y0LPfibWcNpfp0AhxKzyqT1GRRlKTjiBA6WNJIJIEeqh/nfOnwM0UQKRnt+2qeV3u00a5lrvJtEy7nq+s7xYtpVAsCvn5T0U1/8IHkxt
—–END CERTIFICATE—–
Entering the wrapped key into the Public Key or Certificate box on the jwt.io website will successfully verify the signature of the JWT.
HI Nick,
it is good article and neatly explain with clear text.
In my case in her “kid”: “xxxx” is exist but same key when i looking jwts_keys 3 list is coming but none of the KID key is matching with header.
what colud be the issue.
access_token generated on Azure Cloud using that token i am connectiong Windows Authentication API hosted in on-premises web server using Application Proxy connector.
please guide me
HI, please connect with me on Twitter (@thenickrandolph) or via email and I can try to assist.
Hei Nick,
I am facing the similar issue which jainshankar is facing, any luck with this. ?
KeyId is not present in public keys.
Thanks & Regards
Hi Nick,
I’ve the same problem, my kid is not present at https://login.microsoftonline.com/{my_tentant}/discovery/v2.0/keys
I was having a similar issue and found:
If your app has custom signing keys as a result of using the claims-mapping feature,
you must append an appid query parameter containing the app ID to get a jwks_uri pointing to your app’s signing key information, which should be used for validation.
Like this: https://login.microsoftonline.com/{tenant}/discovery/keys?appid={appid}
https://docs.microsoft.com/en-us/azure/active-directory/develop/access-tokens#validating-the-signature
Hi Nick.
I have received Token from AZURE AD and can browse the public key from URL-https://login.microsoftonline.com/{tenant}/discovery/keys?appid={appid}
I found the Kid from the header from the token and find the x5c value from keys. and tried to validate the signature via- https://jwt.io and paste the value inside
——–BEGIN CERTIFICATE—–
X5c value
—–END CERTIFICATE—–
JWT.io display invalid signature. Please suggest.
The only thought I had is that the certificate might be in a different format that what’s expected by jwt.io.
i have the same problem ;(
For those having same issue.
Problem might be with number of dashes.
jwt.io verifies signature only with exactly 5 dashes before and after the BEGIN/END CERTIFICATE. Also make sure, thare aren’t any spaces between text and dashes.
—–BEGIN CERTIFICATE—–
x5c cert
—–END CERTIFICATE—–