JWT Auth Library
A lightweight, framework-agnostic JWT token validation library with support for multiple authentication providers and easy integration with web frameworks.
Features
- 🔐 Framework Agnostic - Works with FastAPI, Flask, Django, CLI tools, background workers, and any Python application
- 🎯 Provider Pattern - Support for multiple JWT providers (Generic JWT, Casdoor, extensible for others)
- ⚡ Async/Await Support - Built for modern Python async applications
- 🛡️ Type Safe - Full type hints and dataclass-based configuration
- 🔧 Easy Integration - Simple adapters for popular web frameworks
- 🚨 Comprehensive Errors - Detailed error codes and messages for all failure scenarios
Installation
# Basic installation
pip install jwt-auth-lib
# With Casdoor support
pip install jwt-auth-lib[casdoor]
# With FastAPI adapter
pip install jwt-auth-lib[fastapi]
# With all optional dependencies
pip install jwt-auth-lib[all]
Quick Start
Generic JWT Validation
import asyncio
from jwt_auth import JWTProvider, JWTConfig
async def main():
# Configure JWT validation
config = JWTConfig(
certificate="-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----",
algorithms=["RS256"],
audience="your-audience",
issuer="your-issuer"
)
# Create provider
auth_provider = JWTProvider(config)
# Validate token
try:
user = await auth_provider.validate_token("your.jwt.token")
print(f"Authenticated user: {user.email}")
print(f"User roles: {user.roles}")
except AuthError as e:
print(f"Authentication failed: {e.code} - {e.message}")
asyncio.run(main())
Casdoor Integration
from jwt_auth import CasdoorProvider, CasdoorConfig
# Configure Casdoor
config = CasdoorConfig.from_env() # Loads from environment variables
# Create provider
auth_provider = CasdoorProvider(config)
# Validate token
user = await auth_provider.validate_token(token)
FastAPI Integration
from fastapi import FastAPI, Depends
from jwt_auth import CasdoorProvider, CasdoorConfig, User
from jwt_auth.adapters.fastapi import create_auth_dependency
app = FastAPI()
# Setup authentication
config = CasdoorConfig.from_env()
auth_provider = CasdoorProvider(config)
get_current_user = create_auth_dependency(auth_provider)
@app.get("/profile")
async def get_profile(user: User = Depends(get_current_user)):
return {
"user_id": user.id,
"email": user.email,
"name": user.name,
"roles": user.roles
}
@app.get("/admin")
async def admin_only(user: User = Depends(get_current_user)):
if not user.has_role("admin"):
raise HTTPException(403, "Admin role required")
return {"message": "Admin access granted"}
Configuration
Environment Variables (Casdoor)
CASDOOR_ENDPOINT=https://auth.your-domain.com
CASDOOR_CLIENT_ID=your-client-id
CASDOOR_CLIENT_SECRET=your-client-secret
CASDOOR_CERTIFICATE="-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----"
CASDOOR_ORG_NAME=your-org
CASDOOR_APP_NAME=your-app
Programmatic Configuration
from jwt_auth import CasdoorConfig
config = CasdoorConfig(
endpoint="https://auth.your-domain.com",
client_id="your-client-id",
client_secret="your-client-secret",
certificate="-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----",
org_name="your-org",
app_name="your-app"
)
Framework-Agnostic Usage
CLI Tool
#!/usr/bin/env python3
import asyncio
import sys
from jwt_auth import CasdoorProvider, CasdoorConfig, AuthError
async def validate_token_cli():
if len(sys.argv) != 2:
print("Usage: python validate.py <token>")
return
config = CasdoorConfig.from_env()
auth_provider = CasdoorProvider(config)
try:
user = await auth_provider.validate_token(sys.argv[1])
print(f"✅ Valid token for: {user.email}")
except AuthError as e:
print(f"❌ Invalid token: {e.code}")
if __name__ == "__main__":
asyncio.run(validate_token_cli())
Background Worker
from jwt_auth import CasdoorProvider, CasdoorConfig
class AuthenticatedWorker:
def __init__(self):
config = CasdoorConfig.from_env()
self.auth_provider = CasdoorProvider(config)
async def process_message(self, message_data):
try:
user = await self.auth_provider.validate_token(
message_data["auth_token"]
)
await self.do_work(user, message_data["payload"])
except AuthError as e:
print(f"Skipping message: {e.code}")
Error Handling
The library provides specific exception types for different failure scenarios:
from jwt_auth import (
AuthError, # Base exception
TokenExpiredError, # Token has expired
InvalidSignatureError, # Invalid signature
InvalidTokenError, # Malformed token
MissingTokenError, # No token provided
InvalidAudienceError, # Wrong audience
InvalidIssuerError, # Wrong issuer
)
try:
user = await auth_provider.validate_token(token)
except TokenExpiredError:
# Handle expired token - maybe redirect to login
pass
except InvalidSignatureError:
# Handle invalid signature - security concern
pass
except AuthError as e:
# Handle any other auth error
print(f"Auth failed: {e.code} - {e.message}")
User Object
The library returns a standard User object regardless of the authentication provider:
@dataclass
class User:
id: str # Unique user identifier
email: str # User email address
name: str # User's name
display_name: Optional[str] # Display name (if different from name)
avatar: Optional[str] # Avatar URL
roles: List[str] # User roles
permissions: List[str] # User permissions
metadata: Dict[str, Any] # Provider-specific data
# Utility methods
def has_role(self, role: str) -> bool
def has_permission(self, permission: str) -> bool
def has_any_role(self, roles: List[str]) -> bool
def has_all_roles(self, roles: List[str]) -> bool
Publishing to PyPI
This library includes a Docker-based publishing system for consistent, isolated uploads to PyPI.
Quick Publishing
# Navigate to library directory
cd lib/jwt_auth
# Test upload (recommended first)
./publish.sh --test
# Production upload
./publish.sh --prod
# Both Test PyPI and Production PyPI
./publish.sh --both
Requirements
- Docker installed and running
- PyPI API tokens configured in
~/.pypirc
See DOCKER_PUBLISH.md for detailed instructions.
Development
# Install development dependencies
pip install -e .[dev]
# Run tests
pytest
# Run linting
black .
flake8 .
mypy .
# Run type checking
mypy jwt_auth/
# Validate package before publishing
./publish.sh --dry-run
License
MIT License - see LICENSE file for details.
Contributing
Contributions are welcome! Please read CONTRIBUTING.md for guidelines.
Support
- GitHub Issues: https://github.com/yourusername/jwt-auth-lib/issues
- Documentation: https://jwt-auth-lib.readthedocs.io/
Metadata
Release files for andspace-jwt-auth 1.2.7
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| andspace_jwt_auth-1.2.7.tar.gz | 17.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| andspace_jwt_auth-1.2.7-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 38.7 kB
Release files / andspace_jwt_auth-1.2.7.tar.gz
| Download URL | andspace_jwt_auth-1.2.7.tar.gz |
|---|---|
| Size | 17.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6716525973d7a261e5faf49ae6916f064b8ec87413a0bc6a990ff92ca27ad94c
|
|
BLAKE2b-256 checksum How to use checksums |
ad4403985c899e05eeea67a839e502dbee2121808db48e41dfde37b9fb279f92
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.13
|
Release files / andspace_jwt_auth-1.2.7-py3-none-any.whl
| Download URL | andspace_jwt_auth-1.2.7-py3-none-any.whl |
|---|---|
| Size | 20.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c75c8d091a64ceed228cc451ce63f9de666608a626819bfda742f9f8816ecc00
|
|
BLAKE2b-256 checksum How to use checksums |
d81b363d8c566e10f2a51db9c3e9a1f49dff3d6e73760c61dc09ddeb36384c5c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.13
|