Skip to main content

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

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

andspace_jwt_auth-1.2.2.tar.gz (17.8 kB view details)

Uploaded Source

Built Distribution

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

andspace_jwt_auth-1.2.2-py3-none-any.whl (20.9 kB view details)

Uploaded Python 3

File details

Details for the file andspace_jwt_auth-1.2.2.tar.gz.

File metadata

  • Download URL: andspace_jwt_auth-1.2.2.tar.gz
  • Upload date:
  • Size: 17.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.13

File hashes

Hashes for andspace_jwt_auth-1.2.2.tar.gz
Algorithm Hash digest
SHA256 cf7f7a23e4341f3ed3d8edb4fb1d609c6ee81b2d0bd48a434859133eb621707e
MD5 d11cf98a1a643e7eb38e1dfcd9fe1ba1
BLAKE2b-256 45366c74fc9b632f9533bc5507fc092f43aaed8cddc88d78044db42a80c1c295

See more details on using hashes here.

File details

Details for the file andspace_jwt_auth-1.2.2-py3-none-any.whl.

File metadata

File hashes

Hashes for andspace_jwt_auth-1.2.2-py3-none-any.whl
Algorithm Hash digest
SHA256 b553dd30fc80f8e94c7b6e79527a226c32ad8cee9dff7b148b4776606a41cf0f
MD5 b3f49f85f9a47ae1b40402d7f9d0535a
BLAKE2b-256 3c661be2b02c22124b1f1d6f14af28627c78995229fa631d3c51cce038f9c5af

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