Identity & SSO
LLMProxy supports stateless multi-provider OIDC/JWT authentication with role-based access control.
Auth Model — Fail-Closed (v1.10.0)
All paths under /api/v1/*, /admin/*, and /metrics are denied by default at the ASGI middleware layer in proxy/app_factory.py — before any route handler runs. Only paths in _PUBLIC_EXACT are reachable without credentials.
See Security Overview for the full whitelist and pipeline diagram.
Authentication Chain
For requests that reach a route handler, LLMProxy tries authentication methods in order:
- JWT — Bearer token verified via OIDC JWKS
- API Key — Static key from
LLM_PROXY_API_KEYS - Tailscale — Machine/user identity via LocalAPI socket
OIDC Providers
Configured via config.yaml:
identity:
enabled: true
default_role: "user"
providers:
- name: google
client_id_env: "OIDC_GOOGLE_CLIENT_ID"
- name: microsoft
client_id_env: "OIDC_MICROSOFT_CLIENT_ID"
- name: apple
client_id_env: "OIDC_APPLE_CLIENT_ID"
session_ttl: 3600Providers are auto-configured via well-known OIDC discovery endpoints. JWKS keys are cached with 1-hour TTL and auto-refreshed on rotation.
Token Exchange
The OAuth flow:
- Frontend opens provider OAuth popup
- User authenticates, receives
id_token - Frontend calls
POST /api/v1/identity/exchangewith the external JWT - LLMProxy verifies the JWT via JWKS, issues an internal proxy session token
- Internal token stored in
localStorage, sent as Bearer on subsequent requests
RBAC
Four built-in roles with granular permissions:
| Role | Key Permissions |
|---|---|
| admin | Full access: proxy, registry, chat, logs, plugins, users, budget |
| operator | Proxy toggle, registry write, plugins manage, features toggle |
| user | Proxy use, registry read, chat, logs read |
| viewer | Registry read, logs read only |
Role Mapping
Map email addresses to roles:
identity:
role_mappings:
"admin@example.com": ["admin"]
"ops@example.com": ["operator"]Roles are also persisted in the SQLite user_roles table.
Zero-Trust
- Tailscale LocalAPI: Verifies machine/user identity via Unix socket (
whoisAPI) - URL Injection Prevention: All user-supplied IPs/URLs escaped via
urllib.parse.quote()
Frontend OAuth
The SOC dashboard (ui/services/auth.js) implements a popup-based OAuth flow:
- Click provider button → popup opens OIDC authorize URL
oauth-callback.htmlrelays token viapostMessage- Token exchange converts external JWT to internal session
- If identity is enabled and no valid session exists, a glassmorphism login overlay is shown
- Manual API key entry available as fallback
