Decoding azure access token obtained by client credential flow

1.4k Views Asked by At

Got access token using azure.identity ClientSecretCredential client credential flow but when trying to decode using the PyJwt library giving me the below error.

ValueError: Could not deserialize key data. The data may be in an incorrect format or it may be encrypted with an unsupported algorithm.

decoding like below:

 jwt.decode(
            token,
            client_secret, # same client secret used in generating the access token
            options={"verify_signature": True},
            algorithms=["RS256"],
        )

If i keep the verify_signature to false then i'm able to decode. Also tried passing issue and audience while decoding but didnt work.

 issuer="https://login.microsoftonline.com/<tenant-id>/",
 aud="<client_id>"
1

There are 1 best solutions below

0
On

I tried in my environment and got the below results:

You can use the below code to decode the access token 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"]


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

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

So, I created it with my own API as like below:

enter image description here

Reference:

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.