Skip to content

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

@a-kuchinski

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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions