Skip to main content

Django middleware to validate Azure AD JWT tokens and enrich requests with user data

Project description

django-azuread-token-validator (azvalidator)

Django middleware for validating JWT tokens issued by Azure AD and enriching the request object with additional user profile information. This middleware is designed exclusively for use with Django REST Framework (DRF) to securely and seamlessly protect API routes.


Installation

You can install the package via pip directly from PyPI (or your private repository):

pip install django-azuread-token-validator

Or, if you prefer to install it from the local source code:

git clone https://github.com/MarlonPassos/django-azuread-token-validator.git
cd django-azuread-token-validator
pip install .

Middleware Configuration

1. Add the middleware to your settings.py

Include the full path of the middleware in the MIDDLEWARE list:

MIDDLEWARE = [
    # Default Django middlewares...
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',

    # Azure AD validation middleware
    'azvalidator.middleware.AzureADTokenValidatorMiddleware',  # adjust the path as needed

    # Other middlewares...
]

2. Environment variables for configuration

In settings.py, configure the following variables:

# Azure AD JWKS endpoint URL (to fetch public verification keys)
AZURE_AD_JWKS_URL = "https://login.microsoftonline.com/<tenant_id>/discovery/keys"

# JWKS cache timeout in seconds (default: 3600)
AZURE_AD_CACHE_TIMEOUT = 3600

# Enable or disable token signature verification (default: True)
AZURE_AD_VERIFY_SIGNATURE = True

# Expected JWT token issuer (default: https://login.microsoftonline.com/<tenant_id>/v2.0)
AZURE_AD_ISSUER_URL = "https://login.microsoftonline.com/<tenant_id>/v2.0"

# Expected audience identifier in the JWT token (usually the client_id or App ID URI)
AZURE_AD_AUDIENCE = "api://<client_id>"

# List of accepted JWT algorithms (default: ["RS256"])
AZURE_AD_ALGORITHMS = ["RS256"]

# Default username for Client Credentials tokens (app-to-app)
AZURE_AD_DEFAULT_APP_USERNAME = "app"

# Default role for Client Credentials tokens
AZURE_AD_DEFAULT_APP_ROLE = "AppRole"

# External service URL to fetch additional user information (optional)
AZURE_AD_AUX_USERINFO_SERVICE_URL = "https://api.example.com/userinfo"

# Timeout for requests to the additional service in seconds (default: 10)
AZURE_AD_AUX_USERINFO_SERVICE_TIMEOUT = 10

# Mapping between fields returned by the additional service and request attributes
# Format: {"service_field": "request_attribute_name"}
AZURE_AD_AUX_USERINFO_MAPPING = {
    "department": "azure_department",
    "department_number": "azure_department_number",
    "company": "azure_company",
    "employee_number": "azure_employee_role",
}

3. Usage in views

To enable token validation in a DRF view or viewset, set the attribute azure_authentication = True in the view class:

from rest_framework import viewsets, routers
from rest_framework.response import Response


class DummyViewSet(viewsets.ViewSet):
    azure_authentication = True

    def list(self, request):
        return Response(
            {
                "user": getattr(request, "azure_username", None),
                "roles": getattr(request, "azure_roles", []),
                "email": getattr(request, "azure_email", None),
            }
        )

Application Authentication in Azure AD

The package provides a utility function to authenticate applications in Azure AD using the client_credentials flow. This function is useful for scenarios where an application needs to communicate with another protected application.

Function: generate_app_azure_token

The generate_app_azure_token function returns a valid access token for the application. The token is cached and automatically renewed upon expiration.

Example usage:

from azvalidator.utils import generate_app_azure_token

# Get the access token
access_token = generate_app_azure_token()
print(f"Access token: {access_token}")

Ensure the following variables are configured correctly for the function to work:

# Azure AD authentication endpoint URL
AZURE_AD_URL = "https://login.microsoftonline.com"

# Azure AD Tenant ID
AZURE_AD_TENANT_ID = "<tenant_id>"

# Grant type (must be "client_credentials")
AZURE_AD_APP_GRANT_TYPE = "client_credentials"

# Client ID registered in Azure AD
AZURE_AD_APP_CLIENT_ID = "<client_id>"

# Client secret registered in Azure AD
AZURE_AD_APP_CLIENT_SECRET = "<client_secret>"

# Required access scope
AZURE_AD_APP_SCOPE = "https://graph.microsoft.com/.default"

External Service for Additional User Information

Purpose

The middleware can enrich the request object with extra data fetched from an external service, in addition to the basic Azure AD token data.

How it works

  • After validating the token, the middleware makes an HTTP GET request to:

    {AZURE_AD_AUX_USERINFO_SERVICE_URL}/{username}/
    
  • If configured, it sends a Bearer token via the Authorization header for authentication.

  • The external service must return a JSON response with the additional user data.

External service specifications

  • Endpoint: REST, accepting GET requests at the URL /username/
  • Authentication: Optional via Bearer Token
  • Response: JSON with fields containing user data (example below)

Example JSON response:

{
  "department": "Information Technology",
  "department_number": "123",
  "company": "MyCompany",
  "employee_number": "456789",
  "other_field": "value"
}

Mapping data to the request

The dictionary AZURE_AD_AUX_USERINFO_MAPPING defines which fields from the JSON response will be added to the request object and under which names, for example:

AZURE_AD_AUX_USERINFO_MAPPING = {
    "department": "azure_department",
    "department_number": "azure_department_number",
    "company": "azure_company",
    "employee_number": "azure_employee_role",
}

Timeout and Resilience

  • Request timeout is configurable via AZURE_AD_AUX_USERINFO_SERVICE_TIMEOUT (default: 10 seconds).
  • If the service is unavailable or an error occurs, the middleware logs the failure and continues the request without additional data.

Tests

The package's test suite covers the main middleware scenarios to ensure robustness:

  • Validation of a valid token with the preferred_username claim.
  • Rejection of a token without the preferred_username claim (returns HTTP 401).
  • Rejection of a token with an invalid signature.
  • Rejection of an expired token.
  • Handling of Client Credentials tokens (app-to-app).
  • Enrichment of the request with additional information via an external service.
  • Appropriate responses with status 401 or 500 based on detected errors.

Basic test example:

cd tests && pip install -r requirements.txt && python manage.py test

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django_azuread_token_validator-0.1.3.tar.gz (10.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

File details

Details for the file django_azuread_token_validator-0.1.3.tar.gz.

File metadata

File hashes

Hashes for django_azuread_token_validator-0.1.3.tar.gz
Algorithm Hash digest
SHA256 0502aebab2ac635e800d5a3188b5be08ef90b6c143dff130817b5ed8afb9bd52
MD5 28913c1588a3598e3736bd718adcee01
BLAKE2b-256 a314dbef074f66f251678216d0fec00aee2c28601d99e2f3517784bd03a004b8

See more details on using hashes here.

File details

Details for the file django_azuread_token_validator-0.1.3-py3-none-any.whl.

File metadata

File hashes

Hashes for django_azuread_token_validator-0.1.3-py3-none-any.whl
Algorithm Hash digest
SHA256 e3cdc905960bfc966636d4f64c7f205893eed274052a63ec84edc626e49947bd
MD5 3aa7244b629aacbc6dee16f5279726d4
BLAKE2b-256 7866a9088cc2d1b0224ca0e535a01f58fd7ffcb53807ee7142675a6f0b99d83e

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page