Skip to main content

Django middleware and auth backend for OIDC authentication via AWS ALB

Project description

django-amzn-oidc-auth

Django middleware and authentication backend for apps deployed behind an AWS Application Load Balancer (ALB) with OIDC authentication enabled.

How it works

When an ALB is configured with OIDC, it handles the full OAuth2 flow and injects a signed JWT into every upstream request via the x-amzn-oidc-data header. This package:

  1. Validates the JWT signature using the ALB's region-specific public key (fetched from AWS and cached)
  2. Maps the decoded claims to a Django User (creating one on first login if configured)
  3. Establishes a normal Django session — groups, permissions, @login_required, and request.user all work as usual

Installation

pip install django-amzn-oidc-auth

or

uv add django-amzn-oidc-auth

Setup

Add to INSTALLED_APPS, MIDDLEWARE, and AUTHENTICATION_BACKENDS:

INSTALLED_APPS = [
    ...
    "django_amzn_oidc_auth",
]

MIDDLEWARE = [
    "django.contrib.sessions.middleware.SessionMiddleware",
    "django.contrib.auth.middleware.AuthenticationMiddleware",
    "django_amzn_oidc_auth.middleware.AmznOidcMiddleware",
    ...
]

AUTHENTICATION_BACKENDS = [
    "django_amzn_oidc_auth.backends.AmznOidcAuthBackend",
    "django.contrib.auth.backends.ModelBackend",
]

Settings

Setting Default Description
AWS_REGION required Region used to fetch ALB public keys
AMZN_OIDC_BYPASS_VALIDATION False Skip JWT signature check — dev only
AMZN_OIDC_AUTO_CREATE_USERS True Create Django users on first login
AMZN_OIDC_EXEMPT_PATHS [] Paths that skip OIDC auth (e.g. health checks)
AMZN_OIDC_USERNAME_CLAIM sub OIDC claim to use as the Django username. Defaults to sub. Set this if your IdP uses a different stable identifier (e.g. "preferred_username"). Changing this on an existing deployment will break logins for users whose accounts were created under the old claim value.
AMZN_OIDC_AUDIENCE None Expected value of the JWT aud claim. When set, tokens whose aud does not match are rejected — recommended when multiple applications share the same ALB to prevent cross-application token replay. When unset, audience validation is skipped.

Usage in views

Once the middleware is active, every authenticated request has a populated request.user (a standard Django User instance) and request.oidc_claims (the raw decoded JWT payload).

Function-based views

from django.contrib.auth.decorators import login_required
from django.http import JsonResponse

@login_required
def profile(request):
    return JsonResponse({
        "username": request.user.username,
        "email": request.user.email,
    })

def debug_claims(request):
    # Raw OIDC payload — useful during development
    return JsonResponse(request.oidc_claims)

Class-based views

from django.contrib.auth.mixins import LoginRequiredMixin
from django.views import View
from django.http import JsonResponse

class ProfileView(LoginRequiredMixin, View):
    def get(self, request):
        return JsonResponse({"username": request.user.username})

LoginRequiredMixin and @login_required both work because the middleware establishes a normal Django session — the auth decorators don't know or care that authentication came from an ALB header.

Checking permissions and groups

Standard Django permission checks work unchanged:

@login_required
def admin_only(request):
    if not request.user.has_perm("myapp.change_widget"):
        return HttpResponseForbidden()
    ...

Health check / unauthenticated paths

Add paths that should bypass OIDC to AMZN_OIDC_EXEMPT_PATHS. The middleware passes these through without checking the x-amzn-oidc-data header, so load-balancer health checks and similar endpoints keep working even before a session exists:

AMZN_OIDC_EXEMPT_PATHS = ["/healthcheck/", "/readyz/"]

Accessing raw OIDC claims

request.oidc_claims contains the full decoded JWT payload from the ALB. This is useful when your OIDC provider includes custom claims (e.g. roles, tenant ID) beyond what Django's User model stores.

Authorising based on a custom claim

from django.http import HttpResponseForbidden

def admin_dashboard(request):
    roles = request.oidc_claims.get("custom:roles", [])
    if "admin" not in roles:
        return HttpResponseForbidden()
    ...

Multi-tenant routing

def my_view(request):
    tenant = request.oidc_claims.get("custom:tenant_id")
    queryset = Widget.objects.filter(tenant=tenant)
    ...

Using a claim as the Django username

If your IdP uses preferred_username (or another claim) as the stable account identifier instead of sub, configure it via AMZN_OIDC_USERNAME_CLAIM:

# settings.py
AMZN_OIDC_USERNAME_CLAIM = "preferred_username"

Note: Only set this on a fresh deployment, or when you are prepared to migrate existing User rows. Changing the claim on an existing deployment means Django will look up users by the new claim value and won't find accounts that were created under the old one.

Enriching the user model from claims

If you need to store extra claim data on first login (e.g. a department or employee ID), subclass the backend:

from django_amzn_oidc_auth.backends import AmznOidcAuthBackend

class MyBackend(AmznOidcAuthBackend):
    def _sync_user_fields(self, user, claims):
        super()._sync_user_fields(user, claims)
        # profile is a OneToOneField added by your app
        user.profile.department = claims.get("custom:department", "")
        user.profile.save()

Register MyBackend in place of (or in addition to) the default in AUTHENTICATION_BACKENDS.

Local development

Set AMZN_OIDC_BYPASS_VALIDATION = True and send an unsigned JWT in the x-amzn-oidc-data header:

python -c "
import jwt, time
print(jwt.encode({'sub': 'dev-user', 'email': 'dev@example.com',
    'iss': 'https://example.com', 'exp': int(time.time()) + 3600},
    'ignored', algorithm='HS256'))
"

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_amzn_oidc_auth-1.0.0rc1.tar.gz (36.7 kB view details)

Uploaded Source

Built Distribution

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

django_amzn_oidc_auth-1.0.0rc1-py3-none-any.whl (7.8 kB view details)

Uploaded Python 3

File details

Details for the file django_amzn_oidc_auth-1.0.0rc1.tar.gz.

File metadata

  • Download URL: django_amzn_oidc_auth-1.0.0rc1.tar.gz
  • Upload date:
  • Size: 36.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.21 {"installer":{"name":"uv","version":"0.11.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for django_amzn_oidc_auth-1.0.0rc1.tar.gz
Algorithm Hash digest
SHA256 150be1ac676d8ef1a4876248f9753101812ae9a36e7d0afba8ef2b51a44e1393
MD5 283c236e4619ad486ff93f1ff19d3cb2
BLAKE2b-256 513f27ee539f1137d742d6c0998f30b219e61f5c055deda76fd8539cd1608b86

See more details on using hashes here.

File details

Details for the file django_amzn_oidc_auth-1.0.0rc1-py3-none-any.whl.

File metadata

  • Download URL: django_amzn_oidc_auth-1.0.0rc1-py3-none-any.whl
  • Upload date:
  • Size: 7.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.21 {"installer":{"name":"uv","version":"0.11.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for django_amzn_oidc_auth-1.0.0rc1-py3-none-any.whl
Algorithm Hash digest
SHA256 89ea1c136df2e609745d738e2debc913658c23b1fc846da806313ec1a6992f5d
MD5 0b60d7b27943528562433cd7f486130c
BLAKE2b-256 39d650d4be5ca5fd8e2bd60a3c949aae55fa471ce97f9f2f4ff4f80ba96f0943

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