Production-ready LDAP authentication and authorization for FastAPI
Project description
fastapi-ldap
Production-ready LDAP authentication and authorization for FastAPI.
Features
- ✅ Async-first design - No blocking LDAP calls in the event loop
- ✅ Security by default - TLS enabled, no anonymous binds, fail-closed behavior
- ✅ Enterprise-ready - LDAP and Active Directory compatible
- ✅ Kubernetes-friendly - Health and readiness checks included
- ✅ FastAPI-native - Idiomatic dependencies and lifespan management
- ✅ Optional caching - Configurable TTL for authentication results
- ✅ Type-safe - Full type hints, Python 3.10+
Installation
pip install fastapi-ldap
Quick Start
from fastapi import Depends, FastAPI
from fastapi_ldap import (
LDAPAuth,
LDAPSettings,
get_current_user,
health_check,
readiness_check,
require_groups,
)
from fastapi_ldap.models import LDAPUser
# Configure LDAP settings
settings = LDAPSettings(
ldap_url="ldaps://ldap.example.com:636",
ldap_base_dn="dc=example,dc=com",
bind_dn="cn=admin,dc=example,dc=com",
bind_password="secret",
)
# Create LDAP auth instance
ldap_auth = LDAPAuth(settings)
# Create FastAPI app with lifespan
app = FastAPI(lifespan=ldap_auth.lifespan)
# Health checks
@app.get("/health")
async def health():
return await health_check()
@app.get("/ready")
async def ready():
return await readiness_check()
# Protected route
@app.get("/protected")
async def protected_route(user: LDAPUser = Depends(get_current_user)):
return {
"username": user.username,
"email": user.email,
"groups": list(user.groups),
}
# Route requiring specific groups
@app.get("/admin")
async def admin_route(
user: LDAPUser = Depends(require_groups("admins", "superusers"))
):
return {"message": f"Welcome, {user.username}!"}
Configuration
Configuration can be provided via environment variables (prefixed with LDAP_) or directly:
from fastapi_ldap import LDAPSettings
settings = LDAPSettings(
# Required
ldap_url="ldaps://ldap.example.com:636",
ldap_base_dn="dc=example,dc=com",
# Bind credentials (required unless allow_anonymous=True)
bind_dn="cn=admin,dc=example,dc=com",
bind_password="secret",
# TLS (enabled by default)
use_tls=True,
tls_ca_cert_file="/path/to/ca.crt",
# Search configuration
user_search_filter="(uid={username})", # Default for OpenLDAP
# user_search_filter="(sAMAccountName={username})", # For Active Directory
# Connection pool
pool_size=10,
pool_timeout=30.0,
# Caching (optional)
cache_enabled=True,
cache_ttl=300, # 5 minutes
)
Environment Variables
All settings can be configured via environment variables:
export LDAP_URL="ldaps://ldap.example.com:636"
export LDAP_BASE_DN="dc=example,dc=com"
export LDAP_BIND_DN="cn=admin,dc=example,dc=com"
export LDAP_BIND_PASSWORD="secret"
export LDAP_CACHE_ENABLED="true"
export LDAP_CACHE_TTL="300"
Important: Passwords with Special Characters
If your password contains special characters (e.g., $, %, &, *, (, ), \, etc.), make sure to properly quote the environment variable to prevent shell interpretation:
# ✅ Correct - use single quotes to prevent shell interpretation
export LDAP_BIND_PASSWORD='pass$word%test&more'
# ✅ Also correct - use double quotes and escape special chars
export LDAP_BIND_PASSWORD="pass\$word%test&more"
# ❌ Wrong - shell will interpret $word as a variable
export LDAP_BIND_PASSWORD=pass$word
Note: LDAP passwords can contain any characters, including special ones and Unicode. The fastapi-ldap library accepts passwords as-is without validation, as LDAP servers handle password validation. The only requirement is that passwords are properly set in environment variables to avoid shell interpretation issues.
Active Directory Example
settings = LDAPSettings(
ldap_url="ldaps://ad.example.com:636",
ldap_base_dn="dc=example,dc=com",
bind_dn="CN=Service Account,CN=Users,DC=example,DC=com",
bind_password="password",
user_search_filter="(sAMAccountName={username})",
user_search_base="CN=Users,DC=example,DC=com",
group_search_filter="(member:1.2.840.113556.1.4.1941:={user_dn})", # Recursive group search
group_attribute="cn",
)
API Reference
Dependencies
get_current_user- Get the current authenticated user (HTTP Basic Auth)require_groups(*groups)- Require user to belong to at least one of the specified groupsrequire_roles(*roles)- Alias forrequire_groups(semantic clarity)
Models
LDAPUser- Immutable user object with:dn- Distinguished Nameusername- Usernameemail- Email address (optional)display_name- Display name (optional)groups- Frozen set of group namesattributes- Additional LDAP attributeshas_group(group)- Check if user belongs to a grouphas_any_group(groups)- Check if user belongs to any grouphas_all_groups(groups)- Check if user belongs to all groups
Health Checks
health_check()- Basic health check (does not verify LDAP)readiness_check()- Verifies LDAP connectivity (for Kubernetes probes)
Security Considerations
- TLS is enabled by default - Disable only for testing in secure environments
- Anonymous binds are disabled by default - Must be explicitly enabled
- Authentication failures are indistinguishable - Prevents user enumeration
- No credential logging - Passwords are never logged
- Fail-closed behavior - If LDAP is unavailable, authentication fails securely
Architecture
The module follows a layered architecture:
- LDAP Client Layer (
client.py) - Isolated from FastAPI, handles connections, retries, timeouts, TLS - Auth Layer (
auth.py) - FastAPI dependencies, converts LDAP errors to HTTP errors - Models (
models.py) - Immutable LDAP user objects - Cache Layer (
cache.py) - Optional caching with configurable TTL - Configuration (
config.py) - Explicit, documented settings
Development
# Install development dependencies
pip install -e ".[dev]"
# Run tests
pytest
# Format code
black fastapi_ldap tests
# Lint code
ruff check fastapi_ldap tests
# Type check
mypy fastapi_ldap
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file fastapi_ldap-0.1.0.tar.gz.
File metadata
- Download URL: fastapi_ldap-0.1.0.tar.gz
- Upload date:
- Size: 21.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.2.1 CPython/3.14.2 Darwin/25.2.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f392e3f0773fedce937df50e88d778daeb39261a26a3d169e47844a820e5aeba
|
|
| MD5 |
f0ad8fd6282a544911c560b6c6fb94fd
|
|
| BLAKE2b-256 |
754f804942a9e33858a226f06283e01745974fbeb9c28ce2fd3db4a2e261b5d1
|
File details
Details for the file fastapi_ldap-0.1.0-py3-none-any.whl.
File metadata
- Download URL: fastapi_ldap-0.1.0-py3-none-any.whl
- Upload date:
- Size: 13.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.2.1 CPython/3.14.2 Darwin/25.2.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b3cd503d3960b8d972b99c74a629892f77ba7c78e56b6c6f797618fe3e3bd15b
|
|
| MD5 |
9f39522cf49188003a03a745712afb13
|
|
| BLAKE2b-256 |
0e5845ced5db8c7d0cd1a1bdbf0ac86268b8e8a073b06231eeaf14cf1a4781df
|