Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
a-kuchinski opened this issue Sep 24, 2024 · 1 comment

Comments

@a-kuchinski
Copy link

a-kuchinski commented Sep 24, 2024

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`.

Upvote & Fund

  • We're using Polar.sh so you can upvote and help fund this issue.
  • We receive the funding once the issue is completed & confirmed by you.
  • Thank you in advance for helping prioritize & fund our backlog.
Fund with Polar
@tim-schilling
Copy link
Member

Have you taken a look at the JWT without verifying the signature to confirm it looks correct? You can do so by disabling the verify_ aspects here:

There may be another call you need to make. The goal here isn't to avoid the error by disabling the checks, but to understand what is being sent so you can make changes to get things to work appropriately.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants