Auth
JWT principals, JWKS rotation, on-behalf-of pattern.
vibes-auth (apps/auth/) is the only place that mints JWTs. Everything
else verifies via auth.omg.dev/.well-known/jwks.json.
Token shape
{
"iss": "https://auth.omg.dev",
"aud": "vibes-infra",
"sub": "user-abc" | "svc:convex" | "svc:worker" | "svc:ci",
"appId": "vibes-infra",
"iat": 1777000000,
"exp": 1808500000, // 1 year for service tokens
"jti": "29629508-..." // for revocation
}- User tokens carry the principal of the logged-in human; minted on login, short-lived.
- Service tokens (
substarts withsvc:) are minted on the auth box viabun apps/auth/scripts/mint.ts <name> <ttlSeconds>. There is no public mint endpoint — minting requires SSH access to the auth box. This is intentional: the only thing that could leak from the network is a single token, never the signing key or a mint capability.
On-behalf-of
A service principal can act for a user by adding X-On-Behalf-Of: <userId>
to its request. Handlers read identity from the resolved Principal struct
(see apps/infra/internal/auth/middleware.go), which carries either:
Principal{ Kind: "user", UserID: "abc" }
Principal{ Kind: "service", Service: "svc:convex", OnBehalfOf: "abc" }Every handler treats both shapes identically for authorization purposes; audit logs distinguish them.
Revocation
Each minted token has a jti. Active tokens live in the service_token
sqld row (apps/auth/src/schema.ts). Revocation is two endpoints:
POST /admin/service-token/revoke— setsrevokedAt. (Run on-box viabun scripts/revoke.ts.)GET /tokens/revoked— returns{ jtis: string[] }. Public, cached 10s at the edge.
Every infra binary polls /tokens/revoked every 30s into a
map[string]struct{} and rejects matching jti on the hot path. So a
revoke takes effect everywhere within ~30s plus edge-cache TTL.
Rotating a service token
bun apps/auth/scripts/mint.ts svc:worker 31536000(1y) on the auth box. Capture the new JWT.- Update the consumer:
svc:convex→bash apps/web/scripts/convex-prod.sh -- npx convex env set VIBES_INFRA_SERVICE_TOKEN <jwt>svc:worker→wrangler secret put VIBES_INFRA_SERVICE_TOKENsvc:ci→gh secret set VIBES_API_KEY --env e2e
- Verify the new key works (one round-trip through the consumer).
bun apps/auth/scripts/revoke.ts <old-jti>to cut off the previous token.
bun apps/auth/scripts/revoke.ts list shows everything live + warns on
tokens within 30 days of expiry.