Skip to content

[django_auth_adfs:157] Error decoding signature: Signature verification failed #346

Description

@a-kuchinski

I've been trying to configure my Django REST Framework app to use django-auth-adfs for Microsoft Entra ID (former Azure AD B2C), but I have an error with signature verification.

Django==5.0.6
djangorestframework==3.15.1
django-auth-adfs==1.14.0

Prior to test oauth2/login page, I tried the example listed in this page

https://django-auth-adfs.readthedocs.io/en/latest/rest_framework.html

with a few additions to make it work with Microsoft Entra:

import os
from pprint import pprint
import requests
from dotenv import load_dotenv

# Load environment variables from .env file
load_dotenv()

# User credentials
user = os.getenv('USER_EMAIL')
password = os.getenv('USER_PASSWORD')

# OAuth 2.0 token endpoint
tenant_id = os.getenv('AAD_B2C_TENANT_ID')
token_url = f"https://login.microsoftonline.com/{tenant_id}/oauth2/token"

# Client (application) ID and secret
client_id = os.getenv('AAD_B2C_CLIENT_ID')
client_secret = os.getenv('AAD_B2C_CLIENT_SECRET')

# API scope
api_scope = f"User.Read api://{client_id}/Backend.Read"

# Prepare the payload
payload = {
    "grant_type": "password",
    "response_type": "token",
    "client_id": client_id,
    "client_secret": client_secret,
    "username": user,
    "password": password,
    "resource": client_id,
    "scope": f"openid profile email {api_scope}",
}

# Request an access token
response = requests.post(
    token_url,
    data=payload,
    verify=True  # Ensure SSL certificates are verified
)

# Check for errors
try:
    response.raise_for_status()
    response_data = response.json()
    access_token = response_data['access_token']
    print('Access token retrieved successfully.')
except requests.exceptions.HTTPError as err:
    print('Error retrieving access token:')
    print(response.text)
    raise SystemExit(err)

# Make a request to the API
headers = {
    'Accept': 'application/json',
    'Authorization': f'Bearer {access_token}',
}

api_response = requests.get(
    'http://localhost:8000/api/contract',
    headers=headers,
    verify=True
)

# Check for errors
try:
    api_response.raise_for_status()
    # Print the API response
    pprint(api_response.json())
except requests.exceptions.HTTPError as err:
    print('API request failed:')
    print(api_response.text)
    raise SystemExit(err)

And the auth works in this case, I successfully getting the access_token and using it to call my app endpoint http://localhost:8000/api/contract.

However, when i'm trying to authorize within my api in the Chrome browser via oauth2/login, I keep getting [django_auth_adfs:157] Error decoding signature: Signature verification failed error.

Here is ADFS config in my DRF app settings.py

...

AUTHENTICATION_BACKENDS = (
    'django_auth_adfs.backend.AdfsAccessTokenBackend',
    'django_auth_adfs.backend.AdfsAuthCodeBackend',
)

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'django_auth_adfs.rest_framework.AdfsAccessTokenAuthentication',
        'rest_framework.authentication.SessionAuthentication',
    ),
    'DEFAULT_RENDERER_CLASSES': [
        'rest_framework.renderers.JSONRenderer',
        'rest_framework.renderers.BrowsableAPIRenderer',
    ],
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
    ),
    'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
    'PAGE_SIZE': 50,  # Default limit if not specified in request
}

AUTH_ADFS = {
    'AUDIENCE': AAD_B2C_CLIENT_ID,
    'CLIENT_ID': AAD_B2C_CLIENT_ID,
    'CLIENT_SECRET': AAD_B2C_CLIENT_SECRET,
    # 'CLAIM_MAPPING': {'first_name': 'given_name',
    #                   'last_name': 'family_name',
    #                   'email': 'upn'},
    'GROUPS_CLAIM': None,
    'MIRROR_GROUPS': False,
    'VERSION': 'v2.0',
    'USERNAME_CLAIM': 'email',
    'DISABLE_SSO': True,
    'TENANT_ID': AAD_B2C_TENANT_ID,
    'RELYING_PARTY_ID': AAD_B2C_CLIENT_ID,
    'CREATE_NEW_USERS': True,
    'LOGIN_EXEMPT_URLS': [
        # '^$',
        '^api',
        # '^admin',
    ],
    'SCOPES': ["openid", "profile", "email", "User.Read", "api://6aeb143f-59f8-4746-ba56-0c489aee6a1f/Backend.Read"],
}

LOGIN_URL = 'django_auth_adfs:login'
LOGOUT_URL = 'django_auth_adfs:logout'
LOGIN_REDIRECT_URL = '/admin/'
REDIRECT_URL = 'django_auth_adfs:callback'

urls.py

"""
from django.conf.urls.static import static
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/', include('api.urls')),
    path('oauth2/', include('django_auth_adfs.urls')),
]

I also tried to change urls to path('oauth2/', include('django_auth_adfs.drf_urls')),as suggested in the docs. But it cause a backend error django.urls.exceptions.NoReverseMatch: 'django_auth_adfs' is not a registered namespace`.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions