azure-active-directoryaccess-token

Signature validation of my Azure access-token, Private-key?


Hello I want to know how to get the keys to verify the access token. I got the x5c from https://login.microsoftonline.com/{{tenantid}}/discovery/keys?appid={{app-id}}

but if i put this key in jwt-decode function its failing. Do i need to do some processing on this key. Its a public key, do i need to know the private key to validate the signature or only public key is enough.

Can you please tell me some basic algo to validate the access_token.


Solution

  • Signature validation of my Azure access token, Private-key?

    I agree with Junnas's comment you need a public key to verify the signature with an Azure access token.

    You can use the below code to decode the access token with the public key using the PyJwt library.

    Code:

    import requests
    import jwt
    from cryptography.hazmat.primitives import serialization
    import json
    
    tenant_id = 'xxxx'
    client_id = 'xxxx'
    client_secret = 'xxxxx'
    
    token_endpoint = f"https://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/token" 
    data = {
          "grant_type": "client_credentials",
          "client_id": f"{client_id}",  
          "client_secret": f"{client_secret}",  
          "scope": "api://your-client-id/.default"
        }
    response = requests.post(token_endpoint, data=data)
    access_token = response.json()["access_token"]
    print(access_token)
    
    response1 = requests.get("https://login.microsoftonline.com/fb134080-e4d2-45f4-9562-f3a0c218f3b0/discovery/keys")
    keys = response1.json()['keys']
    
    token_headers = jwt.get_unverified_header(response.json()['access_token'])
    token_alg = token_headers['alg']
    token_kid = token_headers['kid']
    public_key = None
    for key in keys:
         if key['kid'] == token_kid:
             public_key = key 
    
    
    rsa_pem_key = jwt.algorithms.RSAAlgorithm.from_jwk(json.dumps(public_key))
    rsa_pem_key_bytes = rsa_pem_key.public_bytes(
        encoding=serialization.Encoding.PEM, 
        format=serialization.PublicFormat.SubjectPublicKeyInfo
    ) 
    
    
    decoded_token = jwt.decode(
        response.json()['access_token'], 
        key=rsa_pem_key_bytes,
        verify=True,
        options={"verify_signature": True},
        algorithms=['RS256'],
        audience="api://client_id",
        issuer="https://sts.windows.net/tenant_id/"
    )
    s = json.dumps(decoded_token)
    q = json.dumps(json.loads(s), indent=2)
    print(q)
    

    Output:

    {
      "aud": "api://xxxxx",
      "iss": "https://sts.windows.net/xxxx",
      "iat": 169028xxx,
      "nbf": 1690284xxx,
      "exp": 1690371xxx,
      "aio": "E2ZgYFDetxxxxxvq/ydjjk/BwA=",
      "appid": "d8xxxxx",
      "appidacr": "1",
      "idp": "https://sts.windows.net/xxxxx,
      "oid": "dxxxxx",
      "rh": "xxxxx",
      "roles": [
        "tread.all"
      ],
      "sub": "dxxxxxx5",
      "tid": "fxxx",
      "uti": "wJxxxxxA",
      "ver": "1.0"
    }
    

    enter image description here

    Note: If you are using MS Graph API scopes https://graph.microsoft.com/.default the results JWT would contain a "nonce" in the JWT Header and is not meant to be validated. Except you own API scopes.

    Reference:

    jwt - Using an Azure AD tenant ID - and a valid token issued for a 'app registration'. The signature verification is is failing - Stack Overflow by rukmini.