🎯

better-auth-python

🎯Skill

from naimalarain13/hackathon-ii_the-evolution-of-todo

VibeIndex|
What it does

better-auth-python skill from naimalarain13/hackathon-ii_the-evolution-of-todo

better-auth-python

Installation

Install skill:
npx skills add https://github.com/naimalarain13/hackathon-ii_the-evolution-of-todo --skill better-auth-python
6
AddedJan 27, 2026

Skill Details

SKILL.md

Overview

---

name: better-auth-python

description: Better Auth JWT verification for Python/FastAPI backends. Use when integrating Python APIs with a Better Auth TypeScript server via JWT tokens. Covers JWKS verification, FastAPI dependencies, SQLModel/SQLAlchemy integration, and protected routes.

---

# Better Auth Python Integration Skill

Integrate Python/FastAPI backends with Better Auth (TypeScript) authentication server using JWT verification.

Architecture

```

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”

β”‚ Next.js App │────▢│ Better Auth │────▢│ PostgreSQL β”‚

β”‚ (Frontend) β”‚ β”‚ (Auth Server) β”‚ β”‚ (Database) β”‚

β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

β”‚ β”‚

β”‚ JWT Token β”‚ JWKS Endpoint

β–Ό β–Ό

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”

β”‚ FastAPI Backend β”‚

β”‚ (Verifies JWT tokens) β”‚

β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

```

Quick Start

Installation

```bash

# pip

pip install fastapi uvicorn pyjwt cryptography httpx

# poetry

poetry add fastapi uvicorn pyjwt cryptography httpx

# uv

uv add fastapi uvicorn pyjwt cryptography httpx

```

Environment Variables

```env

DATABASE_URL=postgresql://user:password@localhost:5432/mydb

BETTER_AUTH_URL=http://localhost:3000

```

ORM Integration (Choose One)

| ORM | Guide |

|-----|-------|

| SQLModel | [reference/sqlmodel.md](reference/sqlmodel.md) |

| SQLAlchemy | [reference/sqlalchemy.md](reference/sqlalchemy.md) |

Basic JWT Verification

```python

# app/auth.py

import os

import httpx

import jwt

from dataclasses import dataclass

from typing import Optional

from fastapi import HTTPException, Header, status

BETTER_AUTH_URL = os.getenv("BETTER_AUTH_URL", "http://localhost:3000")

@dataclass

class User:

id: str

email: str

name: Optional[str] = None

_jwks_cache: dict = {}

async def get_jwks() -> dict:

global _jwks_cache

if not _jwks_cache:

async with httpx.AsyncClient() as client:

response = await client.get(f"{BETTER_AUTH_URL}/.well-known/jwks.json")

response.raise_for_status()

_jwks_cache = response.json()

return _jwks_cache

async def verify_token(token: str) -> User:

if token.startswith("Bearer "):

token = token[7:]

jwks = await get_jwks()

public_keys = {}

for key in jwks.get("keys", []):

public_keys[key["kid"]] = jwt.algorithms.RSAAlgorithm.from_jwk(key)

unverified_header = jwt.get_unverified_header(token)

kid = unverified_header.get("kid")

if not kid or kid not in public_keys:

raise HTTPException(status_code=401, detail="Invalid token key")

payload = jwt.decode(token, public_keys[kid], algorithms=["RS256"])

return User(

id=payload.get("sub"),

email=payload.get("email"),

name=payload.get("name"),

)

async def get_current_user(

authorization: str = Header(..., alias="Authorization")

) -> User:

return await verify_token(authorization)

```

Protected Route

```python

from fastapi import Depends

from app.auth import User, get_current_user

@app.get("/api/me")

async def get_me(user: User = Depends(get_current_user)):

return {"id": user.id, "email": user.email, "name": user.name}

```

Examples

| Pattern | Guide |

|---------|-------|

| Protected Routes | [examples/protected-routes.md](examples/protected-routes.md) |

| JWT Verification | [examples/jwt-verification.md](examples/jwt-verification.md) |

Templates

| Template | Purpose |

|----------|---------|

| [templates/auth.py](templates/auth.py) | JWT verification module |

| [templates/main.py](templates/main.py) | FastAPI app template |

| [templates/database_sqlmodel.py](templates/database_sqlmodel.py) | SQLModel database setup |

| [templates/models_sqlmodel.py](templates/models_sqlmodel.py) | SQLModel models |

Quick SQLModel Example

```python

from sqlmodel import SQLModel, Field, Session, select

from typing import Optional

from datetime import datetime

class Task(SQLModel, table=True):

id: Optional[int] = Field(default=None, primary_key=True)

title: str = Field(index=True)

completed: bool = Field(default=False)

user_id: str = Field(index=True) # From JWT 'sub' claim

@app.get("/api/tasks")

async def get_tasks(

user: User = Depends(get_current_user),

session: Session = Depends(get_session),

):

statement = select(Task).where(Task.user_id == user.id)

return session.exec(statement).all()

```

Frontend Integration

Getting JWT from Better Auth

```typescript

import { authClient } from "./auth-client";

const { data } = await authClient.token();

const jwtToken = data?.token;

```

Sending to FastAPI

```typescript

async function fetchAPI(endpoint: string) {

const { data } = await authClient.token();

return fetch(${API_URL}${endpoint}, {

headers: {

Authorization: Bearer ${data?.token},

"Content-Type": "application/json",

},

});

}

```

Security Considerations

  1. Always use HTTPS in production
  2. Validate issuer and audience to prevent token substitution
  3. Handle token expiration gracefully
  4. Refresh JWKS when encountering unknown key IDs
  5. Don't log tokens - they contain sensitive data

Troubleshooting

JWKS fetch fails

  • Ensure Better Auth server is running
  • Check JWKS endpoint is accessible
  • Verify network connectivity

Token validation fails

  • Check issuer/audience match exactly
  • Verify token hasn't expired
  • Check algorithm compatibility (RS256)

CORS errors

  • Configure CORS middleware properly
  • Allow credentials if using cookies
  • Check origin is in allowed list