I have set up an authorization server using AzureAD. For testing it I am currently applying an implicit flow and to get a token and id_token I use https://oidcdebugger.com/.
Now I am trying to figure out how to properly validate a the token on the resource server side.
I always get a jose.exceptions.JWTError: Signature verification failed
.
Can you help me find out what I am doing wrong?
I am really new to JWT validation and probably there is some obvious error somwhere.
As defined by the OIDC metadata endpoint at
https://login.microsoftonline.com/{tenant_id}/v2.0/.well-known/openid-configuration
keys
for signature validation can be found at
https://login.microsoftonline.com/{tenant_id}/discovery/v2.0/keys
.
The key ids on that endpoint match the kid
value in my token headers.
So, I am positive that those are my keys.
They look like this:
{
"kty": "RSA",
"use": "sig",
"kid": "<the-key-id>",
"x5t": "<the-key-id>",
"n": "<a-long-hash>",
"e": "AQAB",
"x5c": ["<a-long-hash-I-guess-thats-the-public-key"],
"issuer": "https://login.microsoftonline.com/<my-tenant-id>/v2.0"
}
In the answer of this post the key is constructed by hand using cryptography.x509
.
I tried the same but I had to change a few details to make it run.
I am .encode
ing the string and I have to pass an iterable to the decode
function.
import requests
from jose import jwt
from cryptography.x509 import load_pem_x509_certificate
from cryptography.hazmat.backends import default_backend
AZURE_TENANT_ID = '<my-tenant-id>'
AZURE_KEYS = requests.get(url='<my-jwks_url>').json()['keys']
PEMSTART = "-----BEGIN CERTIFICATE-----\n"
PEMEND = "\n-----END CERTIFICATE-----\n"
def decode(token: str, keys: list):
token_header = jwt.get_unverified_header(token=token)
x5t = token_header['x5t']
key = [d for d in keys if d['x5t'] == x5t][0]
mspubkey = key['x5c'][0]
cert_str = PEMSTART + mspubkey + PEMEND
cert_obj = load_pem_x509_certificate(cert_str.encode(), default_backend())
public_key = cert_obj.public_key()
return jwt.decode(
token=token,
subject='<my-subject>',
audience='<my-audience>',
issuer=f'https://sts.windows.net/{AZURE_TENANT_ID}/',
algorithms=['RS256'],
key=[public_key])
It seems like I am not supposed to validate the (access) token, only the id_token signature. The validation with jose
also works by just supplying the key dict as keys
argument (no need to construct certificate).
Apparently the (access) token from AzureAD is not necessarily a standard JWT. It's just supposed to be used for accessing the MS GraphAPI: https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/issues/609#issuecomment-529537264