Skip to main content

CodeSena Auth

Production-ready authentication and authorization for FastAPI.


Table of Contents


Installation

Install tc-auth using pip or your preferred package manager:

pip install tc-auth

Ensure you have your database driver installed (e.g. psycopg2-binary for PostgreSQL, asyncpg, or pymysql):

pip install psycopg2-binary

Quick Start

To eliminate circular imports across modular routers, decouple database and auth initialization from the FastAPI app lifecycle:

my_project/
├── connect.py            # 1. Database engine, Auth instantiation & service configs
├── run.py                # 2. FastAPI app assembly, middleware & route registration
├── routers/
│   ├── items.py          # Imports `auth` from `connect` safely
│   └── users.py

1. connect.py (Database Engine & Auth Configuration)

from sqlalchemy import create_engine
from tc_auth import Auth

# Create SQLAlchemy engine
engine = create_engine("postgresql://user:password@localhost:5432/my_db")

# Initialize Auth with database engine
auth = Auth(engine=engine)

# Optional: Configure JWT (built-in defaults available)
auth.jwt.config(
    secret_key="your-super-secret-key",
    algorithm="HS256",
    session_duration_days=7,
    dual_token_mode=True,            # Optional: Enable short-lived access + rotating refresh tokens
    access_token_expire_minutes=15,  # Optional: Access token lifespan in minutes
    refresh_token_expire_days=7,     # Optional: Refresh token lifespan in days
)

# Optional: Configure Email SMTP
auth.email.config(
    host="smtp.example.com",
    port=587,
    username="mailer@example.com",
    password="smtp-password",
    sender="noreply@example.com",
    sender_name="My App",
    use_tls=True,
)

# Optional: Configure Google, GitHub & Discord OAuth
auth.google.config(
    client_id="YOUR_GOOGLE_CLIENT_ID",
    client_secret="YOUR_GOOGLE_CLIENT_SECRET",
    redirect_uri="https://api.example.com/tc-auth/google/callback",
)

2. routers/items.py (Feature Router using Dependencies)

from fastapi import APIRouter, Depends
from connect import auth

router = APIRouter(prefix="/items", tags=["Items"])

# Protected route using auth dependency
@router.get("/")
def get_items(current_user=Depends(auth.deps.get_current_user)):
    account = current_user["account"]
    return {"user_id": account["id"], "name": account["name"], "items": []}

# Admin-only route using role dependency
@router.post("/admin-only")
def create_special_item(admin=Depends(auth.role.require("admin"))):
    return {"status": "created by admin", "account_id": admin["id"]}

3. run.py (FastAPI App Mounting & Server Startup)

import uvicorn
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

from connect import auth
from routers.items import router as items_router

app = FastAPI(title="My Application")

# Configure CORS
app.add_middleware(
    CORSMiddleware,
    allow_origins=["https://app.example.com", "http://localhost:3000"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# Initialize database tables
auth.init()

# Wire tc_auth routes (prefix defaults to "/tc-auth")
auth.include_routes(app, prefix="/tc-auth")

# Include your custom feature routers
app.include_router(items_router)

if __name__ == "__main__":
    uvicorn.run("run:app", host="0.0.0.0", port=8000, reload=True)

Architecture

tc_auth provides a multi-tier security and session validation engine backed by SQLAlchemy:

[ Incoming API Request with Bearer Token ]
                    │
                    ▼
     1. Verify JWT Signature & Expiry
                    │ (Extracts aid, sid, token secret)
                    ▼
     2. Lookup Session in DB by sid
                    │
                    ▼
     3. Verify SHA-256(token secret) == session.token_hash
                    │
                    ▼
     4. Check session.expires_at > now()
                    │
                    ▼
     5. Lookup Account by aid
                    │
                    ▼
   [ Grant Access & Inject Dependencies ]

Core Database Models

  1. Account (accounts): Primary user model with id, uid (UUID), email, handle, phone, password_hash, avatar_url, role, status, and timestamps.
  2. Session (sessions): Server-side active sessions with token_hash (sha256(secret)), ip_address, user_agent, and expires_at.
  3. OTP (otps): 6-digit numeric verification codes with code_hash, purpose (signup, login, reset, verify), attempts, and expires_at.
  4. OAuthAccount (oauth_accounts): Third-party provider links (google, github, discord) bound to account_id with cascade deletion.

Authentication

Password Authentication

  • Signup: POST /tc-auth/signup/password with { "name", "email", "password", "handle"? }
  • Login: POST /tc-auth/login/password with { "identifier", "password" }
  • Password Strength Engine: Enforces minimum 6 characters with $\ge 1$ uppercase letter, $\ge 1$ lowercase letter, and $\ge 1$ numeric digit.

Dual-Token Architecture

  • Single-Token Mode (Default): Returns a long-lived signed JWT access token.
  • Dual-Token Mode (Enabled via dual_token_mode=True): Returns a short-lived Access Token (15 min) and a long-lived Refresh Token (7 days).
  • Refresh Token Endpoint: POST /tc-auth/token/refresh with { "refresh_token": "..." }.

Authorization / RBAC

Declarative dependency injection guards for FastAPI routes:

from fastapi import APIRouter, Depends
from connect import auth

router = APIRouter()

# 1. Inject Current User Context (account + session + JWT claims)
@router.get("/me")
def get_me(user=Depends(auth.deps.get_current_user)):
    return user["account"]

# 2. Require Exact Role
@router.delete("/admin/purge")
def admin_purge(admin=Depends(auth.role.require("admin"))):
    return {"status": "purged"}

# 3. Allow Any of Specified Roles
@router.get("/analytics")
def analytics(user=Depends(auth.role.allow("admin", "manager", "auditor"))):
    return {"data": [1, 2, 3]}

# 4. Block Blacklisted Roles
@router.post("/comment")
def post_comment(user=Depends(auth.role.block("banned", "guest"))):
    return {"message": "Comment posted"}

# 5. Enforce Account Status Guards
@router.post("/transfer")
def transfer_funds(account=Depends(auth.status.require("active"))):
    return {"message": "Transfer successful"}

OAuth

Native integration for Google, GitHub, and Discord OAuth 2.0 / OpenID Connect:

Features:

  • Verified Email Auto-Linking: If a user signs in via OAuth with an email matching an existing account, the provider is automatically linked safely.
  • Authenticated Account Linking: Logged-in users can link secondary providers via POST /tc-auth/account/oauth/link/{provider}.
  • Lockout Prevention Guardrails: Users cannot unlink their last provider via DELETE /tc-auth/account/oauth/{provider} if no password is set, preventing account lockout.

Configuration in connect.py:

auth.google.config(client_id="...", client_secret="...", redirect_uri="https://api.app.com/tc-auth/google/callback")
auth.github.config(client_id="...", client_secret="...", redirect_uri="https://api.app.com/tc-auth/github/callback")
auth.discord.config(client_id="...", client_secret="...", redirect_uri="https://api.app.com/tc-auth/discord/callback")

Dual-pathway authentication inside every email:

  1. One-Click CTA Button ("Click to Proceed"): Clicking the Magic Link verifies and authenticates the user directly.
  2. Manual 6-Digit OTP Code: Prominently displayed for users opening email on a separate device.

Endpoints:

  • POST /tc-auth/send/email/otp/{purpose}: Dispatches OTP + Magic Link email (signup, login, reset, verify).
  • POST /tc-auth/send/email/link/{purpose}: Dedicated Magic Link request route.
  • GET /tc-auth/link/{purpose}: Browser click redirect endpoint (HTTP 307 to frontend callback router).
  • POST /tc-auth/link/{purpose}: Bot-safe headless verification endpoint for SPAs and enterprise email filters.

Sessions

  • Server-Side Session Hashing: Tokens are hashed with SHA-256 before being stored in the database.
  • Single-Device Logout: POST /tc-auth/logout revokes the current session immediately.
  • Logout Everywhere: POST /tc-auth/logout-all terminates all active sessions across all devices for the user.
  • Session Cleanup: DELETE /tc-auth/session/cleanup (superadmin) purges expired sessions.

REST API

All routes are mounted under /tc-auth by default:

Method Endpoint Description Auth Required
POST /tc-auth/signup/password Register with password Public
POST /tc-auth/signup/otp Register and verify OTP simultaneously Public
POST /tc-auth/login/password Login with email/handle/phone & password Public
POST /tc-auth/login/otp Passwordless login with email OTP Public
POST /tc-auth/forgot/password Reset password using verified OTP Public
POST /tc-auth/token/refresh Exchange refresh token for fresh access token Public
POST /tc-auth/send/email/otp/{purpose} Send email OTP & magic link Public
POST /tc-auth/send/email/link/{purpose} Send dedicated magic link email Public
GET /tc-auth/link/{purpose} Browser magic link redirect handler Public
POST /tc-auth/link/{purpose} Programmatic bot-safe magic link verification Public
GET /tc-auth/me Fetch user profile, session, and JWT claims Bearer
PATCH /tc-auth/me Update user profile fields Bearer
PUT /tc-auth/update/password Update current user's password Bearer
POST /tc-auth/logout Revoke current session Bearer
POST /tc-auth/logout-all Revoke all sessions across all devices Bearer
GET /tc-auth/account/oauth/links List connected OAuth providers Bearer
POST /tc-auth/account/oauth/link/{provider} Link secondary OAuth provider Bearer
DELETE /tc-auth/account/oauth/{provider} Safely unlink OAuth provider Bearer
GET /tc-auth/{provider}/login Initiate OAuth login flow Public
GET /tc-auth/{provider}/callback Provider OAuth redirect callback Public
GET /tc-auth/config/pulse Public system health check Public
GET /tc-auth/config/load/ Inspect active service configuration superadmin
GET /tc-auth/config/counts Return total counts across all tables superadmin

Error Handling

All domain exceptions inherit from AuthError with automatic HTTP status code mapping and standardized JSON responses:

{
  "status": false,
  "error": {
    "code": "InvalidCredentialsError",
    "message": "Invalid credentials",
    "details": null
  }
}

Exception Status Code Mapping:

  • 400 Bad Request: AuthError, WeakPasswordError, InvalidFieldError, InvalidEmailPurposeError, InvalidConfigError, OAuthCallbackError.
  • 401 Unauthorized: InvalidCredentialsError, InvalidTokenError, OTPInvalidError, OTPExpiredError.
  • 403 Forbidden: PermissionDeniedError (role failure), AccountStatusError (status failure).
  • 404 Not Found: UserNotFoundError, SessionNotFoundError, OTPNotFoundError, OAuthLinkNotFoundError.
  • 409 Conflict: EmailAlreadyExistsError, HandleAlreadyExistsError, PhoneAlreadyExistsError, OAuthAlreadyLinkedError.
  • 500 Internal Error: DatabaseError, EmailNotConfiguredError, OAuthNotConfiguredError.
  • 502 Bad Gateway: EmailSendError.

Configuration

Configure services live or dynamically on the auth instance:

# JWT Configuration
auth.jwt.config(
    secret_key="your-jwt-secret",
    algorithm="HS256",               # "HS256", "HS384", "HS512"
    session_duration_days=7,
    dual_token_mode=True,
    access_token_expire_minutes=15,
    refresh_token_expire_days=7,
)

# SMTP Email Configuration
auth.email.config(
    host="smtp.resend.com",
    port=587,
    username="resend",
    password="re_your_api_key",
    sender="auth@yourdomain.com",
    sender_name="Your App Security",
    use_tls=True,
)

Documentation

Metadata

Release files for tc-auth 1.5.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for tc-auth 1.5.3
File Size Uploaded
tc_auth-1.5.3.tar.gz 62.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for tc-auth 1.5.3
File Interpreter ABI Platform
tc_auth-1.5.3-py3-none-any.whl Python 3 none any Details

Total release size: 136.3 kB

Release files / tc_auth-1.5.3.tar.gz

Download URL tc_auth-1.5.3.tar.gz
Size 62.8 kB
Tags Source
SHA-256 checksum
How to use checksums
370d5620a5b1fcabf519b51528f484c2fe0c0ff7b58ed58353e7091053334bad
BLAKE2b-256 checksum
How to use checksums
250507ec13f3453bba4c44e9fda20b217bf2022caeaf3acd3c80e5055981b4b4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.9

Release files / tc_auth-1.5.3-py3-none-any.whl

Download URL tc_auth-1.5.3-py3-none-any.whl
Size 73.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a6927740fc355883f4cf04289c4285bf4da30427c701bd70f1acc5e96ddebca9
BLAKE2b-256 checksum
How to use checksums
666a16f2ecd4fd62a035816725adb0d99c9812aeab2a7c66079b771d5aa050dc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.9

Release history Release notifications | RSS feed

This release

1.5.3 This release

2 release files

1.5.2

2 release files

1.5.1

2 release files

1.5.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page