I want to create an API using FastAPI but this API has to recieve a token generated with Azure Active Directory. For now, I only need to read the token and retrieve the info. But I wanna use the Microsoft Authentication Library (MSAL) to achieve it just because it's probable to use other stuff with the library.
My code for now, is this:
import jwt
from jwt import PyJWKClient
JWKS_URL = f"/{settings.TENANT_ID}/discovery/v2.0/keys"
async def validate_token(token):
jwks_client = PyJWKClient(JWKS_URL)
signing_key = jwks_client.get_signing_key_from_jwt(token).key
payload = jwt.decode(
token,
signing_key,
algorithms=[settings.ALGORITHM],
audience=settings.CLIENT_ID,
issuer=f"https://{settings.TENANT_ID}.ciamlogin/{settings.TENANT_ID}/v2.0"
)
return payload
As seen, this use the JWK to decode the token but doesn't use the MSAL package. Any suggestions?
I want to create an API using FastAPI but this API has to recieve a token generated with Azure Active Directory. For now, I only need to read the token and retrieve the info. But I wanna use the Microsoft Authentication Library (MSAL) to achieve it just because it's probable to use other stuff with the library.
My code for now, is this:
import jwt
from jwt import PyJWKClient
JWKS_URL = f"https://login.microsoftonline.com/{settings.TENANT_ID}/discovery/v2.0/keys"
async def validate_token(token):
jwks_client = PyJWKClient(JWKS_URL)
signing_key = jwks_client.get_signing_key_from_jwt(token).key
payload = jwt.decode(
token,
signing_key,
algorithms=[settings.ALGORITHM],
audience=settings.CLIENT_ID,
issuer=f"https://{settings.TENANT_ID}.ciamlogin.com/{settings.TENANT_ID}/v2.0"
)
return payload
As seen, this use the JWK to decode the token but doesn't use the MSAL package. Any suggestions?
Want to create an API using FastAPI but this API has to recieve a token generated with Azure Active Directory using MSAL.
You can use the below sample code that create an API using FastAPI but this API has to recieve a token generated with Azure Active Directory using MSAL.
Code:
import msal
import jwt
import json
from fastapi import FastAPI, HTTPException
from cryptography.hazmat.primitives import serialization
import requests
# Initialize FastAPI app
app = FastAPI()
# Your Azure AD tenant, client ID, and client secret
tenant_id = 'xxxx'
client_id = 'xxx'
client_secret = 'xxx'
# MSAL configuration to acquire token
def acquire_token():
authority = f"https://login.microsoftonline.com/{tenant_id}"
app = msal.ConfidentialClientApplication(
client_id,
client_credential=client_secret,
authority=authority
)
# Acquire token for client credentials flow
result = app.acquire_token_for_client(scopes=["api://fa5ec192-ff39-4399-9f10-609d820ea7b2/.default"])
if "access_token" not in result:
# Log the result for better debugging
print(f"Error result from MSAL: {result}")
raise HTTPException(status_code=400, detail="Failed to obtain access token")
return result["access_token"]
# Fetch JWKS for public key
def get_public_key(kid: str):
jwks_url = f"https://login.microsoftonline.com/{tenant_id}/discovery/v2.0/keys"
response = requests.get(jwks_url)
keys = response.json()['keys']
# Find the matching key by kid
for key in keys:
if key['kid'] == kid:
return key
raise HTTPException(status_code=400, detail="Public key not found")
# Validate token with MSAL and JWK
@app.get("/validate_token")
async def validate_token():
# Acquire the access token using MSAL
access_token = acquire_token()
# Get token header and extract kid
token_headers = jwt.get_unverified_header(access_token)
token_kid = token_headers['kid']
# Fetch the public key using the kid
public_key = get_public_key(token_kid)
# Convert JWK to PEM
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
)
# Decode and verify the token
decoded_token = jwt.decode(
access_token,
key=rsa_pem_key_bytes,
algorithms=['RS256'],
audience=f"api://{client_id}",
issuer=f"https://sts.windows.net/{tenant_id}/"
)
# Return decoded token as a nicely formatted JSON string
return decoded_token
Access the endpoint /validate_token
route to see the decoded token.
http://127.0.0.1:8000/validate_token
Output:
{
"aud": "api://xxxxx",
"iss": "https://sts.windows.net/xxxx",
"iat": 1736163157,
"nbf": 1736163157,
"exp": 1736167057,
"aio": "k2BgYPD6ETbL4I2M5+EtIncvvI+JAwA=",
"appid": "xxxx",
"appidacr": "1",
"idp": "https://sts.windows.net/xxx/",
"oid": "375760b6-497c-4606-b0fe-98eeb25af615",
"rh": "1.AXxxxxx.",
"roles": [
"sampleuser"
],
"sub": "xxxx",
"tid": "xxxxd",
"uti": "xxx",
"ver": "1.0"
}
Reference: Signature validation of my Azure access-token, Private-key? - Stack Overflow by me.