JWSError : Signature verification failed when trying to do jwt.decode in python

Uvnik 0 Reputation points
2025-03-04T03:16:14.5333333+00:00

I have a ReactJS frontend and a python FastAPI backend. I have authenticated the user in the frontend and am sending the retrieved token to the FastAPI backend in the Authentication Header for authenticated endpoints. But the authentication is always failing with "Signature Verification failed" error

import os
import requests
from fastapi import Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer
from jose import jwt, JWTError

# This dependency extracts the token from the "Authorization: Bearer <token>" header.
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

# === Azure AD Configuration ===
TENANT_ID = os.getenv("SSO_TENANT_ID", "<MY TENANT IF>")
CLIENT_ID = os.getenv("SSO_CLIENT_ID", "<MY CLIENT ID>")
SSO_AUTHORITY = f"https://login.microsoftonline.com/{TENANT_ID}"
JWKS_URL = f"{SSO_AUTHORITY}/discovery/v2.0/keys"

# Retrieve and cache the JSON Web Key Set from Azure AD.
try:
    jwks = requests.get(JWKS_URL).json()
except Exception as e:
    raise RuntimeError(f"Unable to retrieve JWKS: {e}")

def get_signing_key(token: str):
    """
    Extract the 'kid' from the token header and find the corresponding key in the JWKS.
    """
    try:
        header = jwt.get_unverified_header(token)
    except JWTError:
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid token header")
    
    kid = header.get("kid")
    if not kid:
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Token missing 'kid' header")
    
    for key in jwks["keys"]:
        if key["kid"] == kid:
            return key
        
    raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Unable to find the appropriate signing key")

def verify_token(token: str):
    """
    Verifies the Azure AD token using the appropriate public key and ensures it was issued
    for our application.
    """
    key = get_signing_key(token)
    try:
        payload = jwt.decode(
            token,
            key,
            algorithms=["RS256"],
            audience=f"{CLIENT_ID}",
            issuer=f"https://sts.windows.net/{TENANT_ID}/"
        )
        return payload
    except JWTError as e:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail=f"Token verification error: {str(e)}"
        )

# The standard dependency to get the current user from the token.
def get_current_user(token: str = Depends(oauth2_scheme)):
    return verify_token(token)


The result of https://login.microsoftonline.com/common/.well-known/openid-configuration is as below:

{
  "token_endpoint": "https://login.microsoftonline.com/common/oauth2/token",
  "token_endpoint_auth_methods_supported": [
    "client_secret_post",
    "private_key_jwt",
    "client_secret_basic"
  ],
  "jwks_uri": "https://login.microsoftonline.com/common/discovery/keys",
  "response_modes_supported": [
    "query",
    "fragment",
    "form_post"
  ],
  "subject_types_supported": [
    "pairwise"
  ],
  "id_token_signing_alg_values_supported": [
    "RS256"
  ],
  "response_types_supported": [
    "code",
    "id_token",
    "code id_token",
    "token id_token",
    "token"
  ],
  "scopes_supported": [
    "openid"
  ],
  "issuer": "https://sts.windows.net/{tenantid}/",
  "microsoft_multi_refresh_token": true,
  "authorization_endpoint": "https://login.microsoftonline.com/common/oauth2/authorize",
  "device_authorization_endpoint": "https://login.microsoftonline.com/common/oauth2/devicecode",
  "http_logout_supported": true,
  "frontchannel_logout_supported": true,
  "end_session_endpoint": "https://login.microsoftonline.com/common/oauth2/logout",
  "claims_supported": [
    "sub",
    "iss",
    "cloud_instance_name",
    "cloud_instance_host_name",
    "cloud_graph_host_name",
    "msgraph_host",
    "aud",
    "exp",
    "iat",
    "auth_time",
    "acr",
    "amr",
    "nonce",
    "email",
    "given_name",
    "family_name",
    "nickname"
  ],
  "check_session_iframe": "https://login.microsoftonline.com/common/oauth2/checksession",
  "userinfo_endpoint": "https://login.microsoftonline.com/common/openid/userinfo",
  "kerberos_endpoint": "https://login.microsoftonline.com/common/kerberos",
  "tenant_region_scope": null,
  "cloud_instance_name": "microsoftonline.com",
  "cloud_graph_host_name": "graph.windows.net",
  "msgraph_host": "graph.microsoft.com",
  "rbac_url": "https://pas.windows.net"
}

I have tried the issuer both as

https://sts.windows.net/{tenantid}/

as well as:

https://login.microsoftonline.com/

But the error persists.

Can anyone please help me resolve this issue

Microsoft Identity Manager
Microsoft Identity Manager
A family of Microsoft products that manage a user's digital identity using identity synchronization, certificate management, and user provisioning.
783 questions
0 comments No comments
{count} votes

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.