Skip to main content

Auth Middleware

PyPI version Python 3.12+ License: MIT Coverage

Async Authentication and Authorization Middleware for FastAPI/Starlette Applications

Auth Middleware is a comprehensive, production-ready authentication and authorization solution for FastAPI and Starlette applications. It provides a pluggable architecture that supports multiple identity providers and authorization backends with async-first design principles.

Features

Authentication Providers

  • Generic OIDC — Any standards-compliant OpenID Connect provider — AWS Cognito, Authentik, Keycloak, Auth0, Okta, ... — via OidcProvider
  • Azure Entra ID — Microsoft Azure Active Directory authentication
  • Basic Auth — Username/password authentication via BasicAuthMiddleware
  • Custom Providers — Extensible architecture via the JWTProvider contract

Authorization & Access Control

  • Group-based Authorization — Role-based access control with user groups
  • Role-based Authorization — Fine-grained role system
  • Permission-based Authorization — Fine-grained permission system
  • SQL Backend Support — PostgreSQL and MySQL for groups/permissions storage via SQLAlchemy
  • Cognito Groups Integration — Direct integration with AWS Cognito groups (cognito:groups claim)
  • Cognito Groups-as-Roles — Map Cognito groups directly to roles
  • Custom Authorization Providers — Build your own via the GroupsProvider, RolesProvider and PermissionsProvider contracts

Performance & Reliability

  • Async-First Design — Built for high-performance async applications
  • JWKS Caching — Intelligent caching of JSON Web Key Sets
  • Connection Pooling — Efficient database and HTTP connections
  • Lazy Loading — User groups and permissions loaded on-demand
  • Error Resilience — Graceful degradation on provider failures

Developer Experience

  • Type-Safe — Full type hints throughout, compatible with mypy strict mode
  • FastAPI Integration — Native dependency injection support
  • Middleware Pattern — Standard ASGI middleware implementation
  • Environment Configuration — 12-factor app configuration support
  • Comprehensive Documentation — Detailed guides and API reference

Installation

# pip
pip install auth-middleware

# poetry
poetry add auth-middleware

# uv (recommended)
uv add auth-middleware

Quick Start

JWT Authentication with AWS Cognito (via generic OIDC)

from fastapi import FastAPI, Depends, Request
from auth_middleware import JwtAuthMiddleware
from auth_middleware.guards import require_user, require_groups
from auth_middleware.providers.oidc.oidc_provider import OidcProvider
from auth_middleware.providers.oidc.oidc_provider_settings import OidcProviderSettings

app = FastAPI()

auth_settings = OidcProviderSettings(
    issuer="https://cognito-idp.us-east-1.amazonaws.com/us-east-1_abcdef123",
    audience="your-app-client-id",  # recommended: rejects tokens issued for other clients
    jwt_token_verification_disabled=False,
)

app.add_middleware(
    JwtAuthMiddleware,
    auth_provider=OidcProvider(settings=auth_settings),
)

# Requires valid authentication
@app.get("/protected", dependencies=[Depends(require_user())])
async def protected_endpoint(request: Request):
    user = request.state.current_user
    return {"message": f"Hello {user.name}", "user_id": user.id}

# Requires group membership
@app.get("/admin", dependencies=[Depends(require_groups(["admin", "moderator"]))])
async def admin_endpoint(request: Request):
    return {"message": "Admin access granted"}

Azure Entra ID

Set the required environment variables (read at module load time):

AUTH_PROVIDER_AZURE_ENTRA_ID_TENANT_ID=your-tenant-id
AUTH_PROVIDER_AZURE_ENTRA_ID_AUDIENCE_ID=your-app-client-id
from auth_middleware import JwtAuthMiddleware
from auth_middleware.providers.azure.entra_id_provider import EntraIDProvider

app.add_middleware(
    JwtAuthMiddleware,
    auth_provider=EntraIDProvider(),
)

Generic OIDC (Authentik, Keycloak, Auth0, Okta, ...)

Works with any standards-compliant OpenID Connect identity provider — the JWKS is discovered automatically from the issuer's .well-known/openid-configuration document.

from auth_middleware import JwtAuthMiddleware
from auth_middleware.providers.oidc.oidc_provider import OidcProvider
from auth_middleware.providers.oidc.oidc_provider_settings import OidcProviderSettings

auth_settings = OidcProviderSettings(
    issuer="https://authentik.example.com/application/o/my-app/",
    audience="your-oidc-client-id",  # recommended: rejects tokens from other clients
)

app.add_middleware(
    JwtAuthMiddleware,
    auth_provider=OidcProvider(settings=auth_settings),
)

Basic Auth

from auth_middleware import BasicAuthMiddleware, hash_password
from auth_middleware.contracts import CredentialsRepository
from auth_middleware.types.user_credentials import UserCredentials

# When creating a user, hash their password once and store the result
# (e.g. hashed_password column) — never store the plaintext password.
stored_hash = hash_password("their-password")

class MyCredentialsRepository(CredentialsRepository):
    async def get_by_id(self, *, id: str) -> UserCredentials | None:
        # Look up the user and return their stored credentials, including
        # the hash produced by hash_password() above
        return UserCredentials(id=id, name="Jane Doe", hashed_password=stored_hash)

app.add_middleware(
    BasicAuthMiddleware,
    credentials_repository=MyCredentialsRepository(),
)

Configuration

Environment Variables

# Core middleware — always read from environment
AUTH_MIDDLEWARE_DISABLED=false
AUTH_MIDDLEWARE_LOG_LEVEL=INFO

# Azure Entra ID — always read from environment at module load (required when using EntraIDProvider)
AUTH_PROVIDER_AZURE_ENTRA_ID_TENANT_ID=your-tenant-id
AUTH_PROVIDER_AZURE_ENTRA_ID_AUDIENCE_ID=your-client-id

# Generic OIDC (e.g. AWS Cognito) — optional; alternative to passing values programmatically to OidcProviderSettings
# OIDC_ISSUER=https://cognito-idp.us-east-1.amazonaws.com/us-east-1_abcdef123
# OIDC_AUDIENCE=your-app-client-id
# JWKS_CACHE_INTERVAL=20      # minutes, default 20
# JWKS_CACHE_USAGES=1000      # verifications before refresh, default 1000

SQL-backed Groups and Permissions

from auth_middleware.providers.oidc.oidc_provider import OidcProvider
from auth_middleware.providers.sqlalchemy.sql_groups_provider import SqlGroupsProvider
from auth_middleware.providers.sqlalchemy.sql_permissions_provider import SqlPermissionsProvider
from auth_middleware.providers.sqlalchemy.async_database import AsyncDatabase
from auth_middleware.providers.sqlalchemy.async_database_settings import AsyncDatabaseSettings

AsyncDatabase.configure(AsyncDatabaseSettings(
    database_url="postgresql+asyncpg://user:pass@localhost/mydb"
))

auth_provider = OidcProvider(
    settings=auth_settings,
    groups_provider=SqlGroupsProvider(),
    permissions_provider=SqlPermissionsProvider(),
)

app.add_middleware(JwtAuthMiddleware, auth_provider=auth_provider)

Cognito Groups Provider

from auth_middleware.providers.oidc.oidc_provider import OidcProvider
from auth_middleware.providers.aws.cognito_groups_provider import CognitoGroupsProvider

# Groups extracted directly from the cognito:groups JWT claim
auth_provider = OidcProvider(
    settings=auth_settings,
    groups_provider=CognitoGroupsProvider(),
)

Usage Examples

Accessing User Information

@app.get("/profile", dependencies=[Depends(require_user())])
async def get_profile(request: Request):
    user = request.state.current_user
    return {
        "id": user.id,
        "name": user.name,
        "email": user.email,
        "groups": await user.groups,
        "permissions": await user.permissions,
    }

Role and Permission Guards

from auth_middleware.guards import require_roles, require_permissions

@app.get("/reports", dependencies=[Depends(require_roles(["analyst", "manager"]))])
async def get_reports(request: Request):
    return {"message": "Reports access granted"}

@app.post("/admin/users", dependencies=[Depends(require_permissions(["user.create"]))])
async def create_user(request: Request):
    return {"message": "User creation allowed"}

curl

curl -H "Authorization: Bearer YOUR_JWT_TOKEN" \
     http://localhost:8000/protected

Package Structure

auth_middleware/
├── jwt_auth_middleware.py       # JwtAuthMiddleware (ASGI)
├── basic_auth_middleware.py     # BasicAuthMiddleware (ASGI)
├── constants.py                 # AUTH_SCHEME_BASIC, AUTH_SCHEME_BEARER
├── contracts/                   # Abstract base classes
│   ├── jwt_provider.py          #   JWTProvider
│   ├── groups_provider.py       #   GroupsProvider
│   ├── roles_provider.py        #   RolesProvider
│   ├── permissions_provider.py  #   PermissionsProvider
│   ├── profile_provider.py      #   ProfileProvider
│   └── credentials_repository.py #  CredentialsRepository
├── guards/                      # FastAPI dependency guards
│   ├── functions.py             #   require_user, require_groups, require_roles,
│   │                            #   require_permissions, get_current_user
│   ├── group_checker.py         #   GroupChecker
│   ├── role_checker.py          #   RoleChecker
│   └── permissions_checker.py   #   PermissionsChecker
├── providers/
│   ├── aws/                     # AWS Cognito groups/roles + auth service (pair with OidcProvider)
│   │   ├── cognito_groups_provider.py
│   │   ├── cognito_groups_as_roles_provider.py
│   │   ├── cognito_profile_provider.py
│   │   └── services/            #   Cognito auth service, M2M detector
│   ├── azure/                   # Azure Entra ID
│   │   ├── entra_id_provider.py
│   │   └── settings.py
│   ├── oidc/                    # Generic OIDC (AWS Cognito, Authentik, Keycloak, Auth0, ...)
│   │   ├── oidc_provider.py
│   │   └── oidc_provider_settings.py
│   └── sqlalchemy/              # SQL-backed authorization
│       ├── sql_groups_provider.py
│       ├── sql_permissions_provider.py
│       ├── async_database.py
│       └── async_database_settings.py
└── exceptions/                  # InvalidTokenException, AuthenticationError, …

Architecture

graph TD
    A[HTTP Request] --> B[JwtAuthMiddleware\nor BasicAuthMiddleware]
    B --> C[JWTBearerManager]
    C --> D[JWTProvider\nOidcProvider · EntraIdProvider]
    D --> E[Token Validation\nJWKS cache + exp/iss/aud]
    E --> F[User object]
    F --> G[GroupsProvider\nCognitoGroupsProvider · SqlGroupsProvider]
    F --> H[PermissionsProvider\nSqlPermissionsProvider]
    F --> I[RolesProvider\nCognitoGroupsAsRolesProvider]
    G --> J[request.state.current_user]
    H --> J
    I --> J
    J --> K[Guards\nrequire_user · require_groups\nrequire_roles · require_permissions]

Core Components

Component Import path Description
JwtAuthMiddleware auth_middleware ASGI middleware for JWT authentication
BasicAuthMiddleware auth_middleware ASGI middleware for Basic Auth
JWTProvider auth_middleware.contracts Abstract base for JWT providers
GroupsProvider auth_middleware.contracts Abstract base for group authorization
RolesProvider auth_middleware.contracts Abstract base for role authorization
PermissionsProvider auth_middleware.contracts Abstract base for permission authorization
CredentialsRepository auth_middleware.contracts Abstract base for Basic Auth credential lookup
require_user auth_middleware.guards Guard: requires authenticated user
require_groups auth_middleware.guards Guard: requires group membership
require_roles auth_middleware.guards Guard: requires role membership
require_permissions auth_middleware.guards Guard: requires specific permissions
get_current_user auth_middleware.guards Dependency: returns current user or None
CognitoGroupsProvider auth_middleware.providers.aws.cognito_groups_provider Groups from cognito:groups claim
CognitoGroupsAsRolesProvider auth_middleware.providers.aws.cognito_groups_as_roles_provider Cognito groups mapped as roles
EntraIDProvider auth_middleware.providers.azure.entra_id_provider Azure Entra ID JWT provider
OidcProvider auth_middleware.providers.oidc.oidc_provider Generic OIDC JWT provider (AWS Cognito, Authentik, Keycloak, Auth0, ...)
SqlGroupsProvider auth_middleware.providers.sqlalchemy.sql_groups_provider DB-backed groups
SqlPermissionsProvider auth_middleware.providers.sqlalchemy.sql_permissions_provider DB-backed permissions

Authenticated User Properties

Available on request.state.current_user:

Property Type Description
id str Unique identifier from the identity provider
name str | None Display name
email EmailStr | None Email address
groups list[str] (async) User groups
roles list[str] (async) User roles
permissions list[str] (async) User permissions

Development

# Clone and set up
git clone https://github.com/impalah/auth-middleware.git
cd auth-middleware
make venv

# Quality checks
make test          # run test suite
make type-check    # mypy strict
make lint          # ruff
make check         # all checks at once

# Build & publish
make build
make publish

Contributing

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'feat: add amazing feature')
  4. Push the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

MIT — see LICENSE for details.


Created by impalah — Made for modern Python async applications

Metadata

Release files for auth-middleware 0.6.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for auth-middleware 0.6.2
File Size Uploaded
auth_middleware-0.6.2.tar.gz 9.0 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for auth-middleware 0.6.2
File Interpreter ABI Platform
auth_middleware-0.6.2-py3-none-any.whl Python 3 none any Details

Total release size: 9.1 MB

Release files / auth_middleware-0.6.2.tar.gz

Download URL auth_middleware-0.6.2.tar.gz
Size 9.0 MB
Tags Source
SHA-256 checksum
How to use checksums
286b01a790078e13892bacf3df2e3e78e15176c1aff87d29ba7ad47c2b0f706f
BLAKE2b-256 checksum
How to use checksums
1cf176ea19664b7d5a76a6137be2493596e561833e37915c488feecc75cf0a78
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.24 {"installer":{"name":"uv","version":"0.12.24","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}

Release files / auth_middleware-0.6.2-py3-none-any.whl

Download URL auth_middleware-0.6.2-py3-none-any.whl
Size 71.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
915eba9017b34b2ff556927d7d3bc205fd0e82d9580d0a76dfbfe5907f4c9f78
BLAKE2b-256 checksum
How to use checksums
e182762d878ca3435b15d070279d89e81e92ae56a43b2090c24ebeb7939e16bf
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.24 {"installer":{"name":"uv","version":"0.12.24","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}

Release history Release notifications | RSS feed

This release

0.6.2 This release

2 release files

0.6.1

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.6

2 release files

0.4.5

2 release files

0.4.4

2 release files

0.4.3

2 release files

0.4.2

2 release files

0.3.9

2 release files

0.3.8

2 release files

0.3.7

2 release files

0.3.5

2 release files

0.3.4

2 release files

0.3.3

2 release files

0.3.2

2 release files

0.2.17

2 release files

0.2.16

2 release files

0.2.15

2 release files

0.2.14

2 release files

0.2.13

2 release files

0.2.9

2 release files

0.2.8

2 release files

0.2.7

2 release files

0.2.6

2 release files

0.2.5

2 release files

0.2.4

2 release files

0.2.3

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.1.18

2 release files

0.1.17

2 release files

0.1.16

2 release files

0.1.14

2 release files

0.1.13

2 release files

0.1.12

2 release files

0.1.11

2 release files

0.1.10

2 release files

0.1.9

2 release files

0.1.8

2 release files

0.1.7

2 release files

0.1.6

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page