Skip to main content

Zero-auth FastAPI middleware for Taleemabad authentication service

Project description

Taleemabad Auth — FastAPI Middleware

Zero-auth FastAPI middleware for Taleemabad authentication service. Clients add 1 line of setup, define 1 enrichment hook, and get full authentication with zero auth code.

Features

Zero Auth Code — No JWT verification, token refresh, or auth logic in your app
Backend-to-Backend Verification — Private key never leaves Taleemabad
Automatic Token Refresh — Expired tokens automatically refreshed
Per-Request Enrichment — Custom fields fetched fresh on every request
Multi-Tenant Ready — Built for organizations
Configurable Token Source — Header (default), session, or cookie

Installation (Phase 3: Integration Testing)

During initial integration testing, copy the middleware directory into your FastAPI project:

# Copy the taleemabad_auth/ directory to your project
cp -r /path/to/taleemabad-auth/middleware/python/taleemabad_auth ./

Your project structure should look like:

your-project/
├── main.py
├── taleemabad_auth/          ← Copy this entire directory
│   ├── __init__.py
│   ├── models.py
│   ├── exceptions.py
│   ├── client.py
│   ├── hooks.py
│   ├── token.py
│   └── middleware.py
└── ...

Then import from your local directory:

from taleemabad_auth import TaleebabadAuth, require_user

Future (Phase 4): After successful integration testing, this will be available on PyPI:

pip install taleemabad-auth

Quick Start

1. Get Credentials

Contact the Taleemabad team with your organization name. You'll receive:

  • TALEEMABAD_CLIENT_ID — your organization UUID
  • TALEEMABAD_CLIENT_SECRET — your organization secret
  • TALEEMABAD_AUTH_SERVICE_URL — the auth service URL

Store in .env:

TALEEMABAD_CLIENT_ID=your-org-uuid
TALEEMABAD_CLIENT_SECRET=your-secret
TALEEMABAD_AUTH_SERVICE_URL=https://auth.taleemabad.com

2. Initialize in Your App

from fastapi import FastAPI, Depends
from taleemabad_auth import TaleebabadAuth, require_user
import os

app = FastAPI()

# Initialize Taleemabad auth
auth = TaleebabadAuth(
    auth_service_url=os.getenv("TALEEMABAD_AUTH_SERVICE_URL"),
    client_id=os.getenv("TALEEMABAD_CLIENT_ID"),
    client_secret=os.getenv("TALEEMABAD_CLIENT_SECRET"),
    token_source="header",  # or "session" or "cookie"
)

# Add to app
app.add_middleware(auth.middleware)

3. Define Enrichment Hook

This is where you fetch custom fields from YOUR database:

@auth.register_hook("enrich_user_claims")
async def enrich_user(user_id: str) -> dict:
    """Fetch custom fields from your database."""
    # Example: fetch user role and permissions from your DB
    user = await db.get_user(user_id)
    return {
        "role": user.role,
        "permissions": {
            "create_class": True,
            "grade_students": user.permissions.get("grade_students", False),
        },
        "organization_id": user.org_id,
    }

4. Protect Routes

Use require_user dependency:

@app.get("/protected")
async def protected_route(user=Depends(require_user)):
    return {"username": user.username, "role": user.role}

# Or access user from request.state
@app.get("/optional")
async def optional_auth(request):
    if hasattr(request.state, "user"):
        return {"username": request.state.user.username}
    else:
        return {"username": "anonymous"}

5. Logout

Add logout endpoint:

@app.post("/api/logout")
async def logout(request):
    await auth.logout(request)
    return {"message": "logged out"}

That's it! ✨

Request Flow

Client Frontend
    │
    ├─→ POST /api/login
    │   └─→ Middleware intercepts response
    │       └─→ Stores tokens (access in localStorage, refresh in cookie)
    │
    ├─→ GET /api/classes (with Authorization: Bearer <access_token>)
    │   └─→ Middleware intercepts request
    │       ├─ Extract token from Authorization header
    │       ├─ POST /api/verify-token (backend-to-backend)
    │       ├─ If expired: POST /api/refresh (auto-refresh)
    │       ├─ Call enrichUserClaims hook
    │       ├─ POST /api/sync-user-profile (store enriched data)
    │       ├─ Attach user + claims to request.state
    │       └─ Continue to route handler
    │
    └─→ POST /api/logout
        └─→ Middleware revokes refresh token

Configuration

Token Source

Control where the middleware extracts the access token from:

auth = TaleebabadAuth(
    token_source="header",      # Authorization: Bearer <token>
    # OR
    token_source="session",     # request.session['taleemabad_token']
    # OR
    token_source="cookie",      # request.cookies['access_token']
)

Timeout

Adjust HTTP request timeout (default 10 seconds):

auth = TaleebabadAuth(
    timeout=5,  # 5 second timeout for all HTTP calls
)

Hooks

enrich_user_claims

Called on every request to fetch custom fields from your database.

@auth.register_hook("enrich_user_claims")
async def enrich(user_id: str) -> dict:
    # Fetch from your database
    user = await db.get_user(user_id)
    return {
        "role": user.role,
        "permissions": user.permissions,
        "organization_id": user.org_id,
    }

on_user_verified (Optional)

Called after user is verified. Use for logging, analytics, etc.

@auth.register_hook("on_user_verified")
async def on_verified(user, claims):
    # Log user verification
    print(f"User {user.username} verified")
    # Or send to analytics service
    await analytics.track_login(user.id)

Error Handling

The middleware is non-fatal:

  • If token verification fails → request continues without user
  • If enrichment hook fails → request continues (empty custom fields)
  • If sync fails → request continues (non-blocking)
  • If token refresh fails → request continues without user

Use require_user dependency to enforce authentication on protected routes:

@app.get("/protected")
async def protected(user=Depends(require_user)):
    # If user is not authenticated, returns 401
    return {"username": user.username}

Testing

Run tests:

# Install dev dependencies
pip install -e ".[dev]"

# Run tests
pytest -v

# With coverage
pytest --cov=taleemabad_auth tests/

Test files:

  • tests/test_client.py — HTTP client tests
  • tests/test_hooks.py — Hook registry tests
  • tests/test_token.py — Token extraction and expiry checks
  • tests/test_middleware.py — Full middleware flow tests

Development

# Install with dev dependencies
pip install -e ".[dev]"

# Format code
black taleemabad_auth/

# Lint
ruff check taleemabad_auth/

# Type check
mypy taleemabad_auth/

Under the Hood

What Middleware Does

  1. Extract Token — From header/session/cookie (configurable)
  2. Verify Backend-to-Backend — Calls /api/verify-token with client credentials
  3. Handle Expiry — If token expired, auto-refreshes via /api/refresh
  4. Enrich with Hook — Calls your enrich_user_claims function
  5. Sync Data — Stores enriched data in Taleemabad via /api/sync-user-profile
  6. Attach to Request — Adds request.state.user and request.state.claims

What Your App Doesn't Need

✅ JWT verification
✅ Token refresh logic
✅ Password hashing
✅ Role checking
✅ Permission validation
✅ Session management
✅ Cookie handling

All handled by the middleware.

API Reference

TaleebabadAuth

Main class for initialization.

auth = TaleebabadAuth(
    auth_service_url: str,      # Taleemabad service URL
    client_id: str,             # Organization UUID
    client_secret: str,         # Organization secret
    token_source: str = "header",  # "header", "session", or "cookie"
    schema: dict = None,        # Optional schema definition
    timeout: int = 10,          # HTTP timeout in seconds
)

# Methods
auth.register_hook(name)        # @auth.register_hook("hook_name")
await auth.logout(request)      # Call from logout endpoint

require_user

FastAPI dependency for protecting routes.

from taleemabad_auth import require_user
from fastapi import Depends

@app.get("/protected")
async def protected(user=Depends(require_user)):
    # user is AuthUser (guaranteed non-None)
    return {"username": user.username}

Models

from taleemabad_auth import AuthUser, TokenClaims

# In your route handler:
@app.get("/me")
async def get_user(request):
    user: AuthUser = request.state.user  # id, username, email, phone
    claims: TokenClaims = request.state.claims  # user + custom_fields
    return {"user": user, "claims": claims}

Support

License

MIT

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

taleemabad_auth-0.1.0.tar.gz (18.4 kB view details)

Uploaded Source

Built Distribution

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

taleemabad_auth-0.1.0-py3-none-any.whl (14.3 kB view details)

Uploaded Python 3

File details

Details for the file taleemabad_auth-0.1.0.tar.gz.

File metadata

  • Download URL: taleemabad_auth-0.1.0.tar.gz
  • Upload date:
  • Size: 18.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.12

File hashes

Hashes for taleemabad_auth-0.1.0.tar.gz
Algorithm Hash digest
SHA256 a90edaf8cdff1255d270183d234111f669196c8f801f0cde40686341657bfa53
MD5 991eb6ff96d5be3e93384301fe130681
BLAKE2b-256 6141c67eea07a06e47802051598043107f7ee1f15f7b794027fb58a08b387571

See more details on using hashes here.

File details

Details for the file taleemabad_auth-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for taleemabad_auth-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 cb1872f873bfb4869d91a364dec2e2860f9b26e41bc0774c2e3fa745a8acf2fe
MD5 c4541426438de77a1e9cee25e0eabacc
BLAKE2b-256 750b92ceb8006387bfc026ac0b1eb73610924f41a3576721efc7702ad60f6de0

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