python - MSAL Package for FastAPI - Stack Overflow

admin2025-05-01  1

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?

Share Improve this question edited Jan 6 at 9:58 Venkatesan 11k2 gold badges5 silver badges20 bronze badges asked Jan 2 at 14:45 Juan Camilo JaramilloJuan Camilo Jaramillo 11 2
  • What you tried for using msal? – JayashankarGS Commented Jan 6 at 7:14
  • Check the below answer. – Venkatesan Commented Jan 6 at 11:44
Add a comment  | 

1 Answer 1

Reset to default 0

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.

转载请注明原文地址:http://www.anycun.com/QandA/1746113189a91851.html