-
-
Notifications
You must be signed in to change notification settings - Fork 106
Description
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`.