Skip to main content

Python

Two patterns. Both are ~30 lines of code.

Your FastAPI / Django / Flask app calls IdentSphere over HTTP for auth flows. The JWT cookie that IdentSphere sets is reused on subsequent requests.

Setup

pip install fastapi httpx python-jose[cryptography] uvicorn
# auth.py
import os
import httpx
from fastapi import FastAPI, Request, HTTPException, Depends
from fastapi.responses import Response
from jose import jwt, JWTError

IDENTSPHERE_URL = os.environ.get("IDENTSPHERE_URL", "http://identsphere:4000")

app = FastAPI()

# ─── proxy login through to IdentSphere ─────────────────────────────────
@app.post("/auth/login")
async def login(request: Request):
body = await request.json()
async with httpx.AsyncClient() as client:
upstream = await client.post(f"{IDENTSPHERE_URL}/v1/auth/login", json=body)
response = Response(content=upstream.content, status_code=upstream.status_code)
# forward the session cookies back to the browser
for cookie in upstream.headers.get_list("set-cookie"):
response.headers.append("set-cookie", cookie)
return response

# ─── validate JWT on protected routes ────────────────────────────
_jwks_cache = None

async def _jwks():
global _jwks_cache
if _jwks_cache is None:
async with httpx.AsyncClient() as client:
r = await client.get(f"{IDENTSPHERE_URL}/.well-known/jwks.json")
_jwks_cache = r.json()
return _jwks_cache

async def current_user(request: Request) -> dict:
token = request.cookies.get("identsphere_at")
if not token:
raise HTTPException(401, "not authenticated")
try:
jwks = await _jwks()
claims = jwt.decode(token, jwks, algorithms=["RS256"], options={"verify_aud": False})
return claims # contains sub, org, email, exp, etc.
except JWTError:
raise HTTPException(401, "invalid token")

# ─── now use it ──────────────────────────────────────────────────
@app.get("/api/me")
async def me(user: dict = Depends(current_user)):
return {"user_id": user["sub"], "org_id": user["org"], "email": user.get("email")}

That's it. Your Python app handles its own business logic; IdentSphere handles register / login / refresh / MFA / passkey / OAuth.

Pattern 2 — JWT validation only

If you don't even need to proxy login, just expose IdentSphere's auth endpoints directly to the browser (different subdomain / path) and have your Python backend ONLY validate tokens.

# minimal validate-only setup
import os, httpx
from jose import jwt, JWTError
from fastapi import FastAPI, Request, HTTPException, Depends

IDENTSPHERE_URL = os.environ["IDENTSPHERE_URL"]
app = FastAPI()
_jwks = None

async def get_jwks():
global _jwks
if _jwks is None:
r = httpx.get(f"{IDENTSPHERE_URL}/.well-known/jwks.json")
_jwks = r.json()
return _jwks

async def auth(request: Request):
token = request.cookies.get("identsphere_at") or request.headers.get("authorization", "").removeprefix("Bearer ")
if not token:
raise HTTPException(401)
try:
return jwt.decode(token, await get_jwks(), algorithms=["RS256"], options={"verify_aud": False})
except JWTError:
raise HTTPException(401)

@app.get("/api/me")
async def me(claims: dict = Depends(auth)):
return {"user_id": claims["sub"], "org_id": claims["org"]}

Calling IdentSphere-managed resources from Python

Need to fetch user profile, change a password, list sessions? Just call IdentSphere's REST API, forwarding the cookies:

async def fetch_profile(request: Request) -> dict:
cookies = {k: v for k, v in request.cookies.items() if k.startswith("identsphere_")}
async with httpx.AsyncClient() as client:
r = await client.get(f"{IDENTSPHERE_URL}/v1/users/me", cookies=cookies)
return r.json()

Every endpoint documented in the API reference works this way.

Django

Same pattern. Wrap in a DjangoView and use Django's session middleware to forward cookies, or use django-cors-headers to let the browser talk directly to IdentSphere.

Flask

Same pattern. Use Flask's request.cookies + requests library.

Caveat: revocation lag

Pattern 2 (validate-only) has a built-in revocation lag of up to (JWKS cache TTL + access token lifetime). Default total is ~15 min. If you need tighter revocation:

  • Drop JWKS cache TTL to a few minutes
  • Reduce IDENTSPHERE_ACCESS_EXPIRY_SECS (default 900) to e.g. 60 seconds
  • Or use Pattern 1, which checks the session table on every request

Full FastAPI starter

A complete working FastAPI starter using IdentSphere lives in the GitHub repo at examples/fastapi-python-starter/ (coming v1.1).