Framework-agnostic JWT token validation library
Project description
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/
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
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 andspace_jwt_auth-1.2.1.tar.gz.
File metadata
- Download URL: andspace_jwt_auth-1.2.1.tar.gz
- Upload date:
- Size: 16.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ac2fc950b0b0cad2bfcc8870400da863e50b6513e78d20a7680809666417e48e
|
|
| MD5 |
40e6fed2455452c8c4ed5470b0f8fe11
|
|
| BLAKE2b-256 |
0c3d21d22256cafd3ab878ffe3d2ac8fa2a7800f1791925fc04b29161bcfe8e5
|
File details
Details for the file andspace_jwt_auth-1.2.1-py3-none-any.whl.
File metadata
- Download URL: andspace_jwt_auth-1.2.1-py3-none-any.whl
- Upload date:
- Size: 19.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e69cb1f089ed0eab4c79b7fe93738a4c38c0dc0b0606169e476fde4acfdb6a26
|
|
| MD5 |
8424700a68f69bbde1bcbaf230ac2ae4
|
|
| BLAKE2b-256 |
69b3e0dc8a3e40921cb5bbb419c6fdbd28d1a241251b9047aa01bbaabf2c8a2e
|