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.3.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.3-py3-none-any.whl (20.9 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: andspace_jwt_auth-1.2.3.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.3.tar.gz
Algorithm Hash digest
SHA256 1ad1b49f9812e3f2cffa29a3186d6f66ebd972988a77b7d1940f33c229fcd089
MD5 6643d28f194b43d78b3d030f264268bd
BLAKE2b-256 c5785b36f18f0eb4d90dd62cc0efcc2e2276787a35a458ff0247653565a2595c

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for andspace_jwt_auth-1.2.3-py3-none-any.whl
Algorithm Hash digest
SHA256 04fb2ae20cd581b814f512793fb0c2ec101cd3adc775ef073fcae608609638c8
MD5 04d2bb63b6161f51e57fb0ebe1dce70a
BLAKE2b-256 e1bb059d1bf9b5887875162c91fa13e61fcee1b88616ae01dc4c18c3204d82b5

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