Authentication
First-party sessions, social OIDC, and the agent-facing authorization server.
Browser sessions
Registration creates a user, workspace, and default project in one transaction, then issues an opaque application session. Next.js stores only the session token in an HttpOnly, SameSite=Lax cookie and forwards it to the API as a Session authorization header.
Passwords use Argon2id. Email addresses are login identifiers; registration does not verify ownership of the address. The starter sends no email and has no verification, password-reset, or account-recovery flow. Password accounts report email_verified: false; a verified upstream OIDC identity can supply that claim.
Migration 0003_remove_email_delivery.sql drops the unused verification and reset-token tables. Existing accounts, passwords, sessions, and OAuth grants are preserved. Previously issued recovery links stop working.
Social OpenID Connect
Configure any conforming provider in OIDC_PROVIDERS_JSON:
{
"google": {
"issuer": "https://accounts.google.com",
"client_id": "your-client-id",
"client_secret": "your-client-secret",
"scopes": ["openid", "profile", "email"]
}
}Start from /auth/start/{provider} on the app. The callback uses state, nonce, and S256 PKCE. The app also creates an HttpOnly browser verifier; the API binds the login and single-use handoff to its SHA-256 challenge. A different browser cannot consume the handoff. Account linking requires both a verified provider email and a verified existing account. An unverified password account cannot be automatically linked by email; use its existing sign-in method. In-flight logins created before the browser-binding migration must restart.
Register this callback with the provider, replacing the slug and public API origin as needed:
https://api.example.com/api/v1/auth/oidc/google/callbackAgent authorization
The API is also an OAuth 2.1/OpenID Connect authorization server for public clients. It exposes:
/.well-known/oauth-authorization-server/.well-known/openid-configuration/.well-known/jwks.json/oauth/authorize,/oauth/token,/oauth/revoke,/oauth/userinfo/oauth/registerwhen dynamic registration is enabled
Authorization codes require S256 PKCE and exact redirect matching. Native loopback callbacks follow RFC 8252 and may vary only their port, which keeps Claude Code's ephemeral callback compatible. Access tokens are RS256 JWTs bound to MCP_RESOURCE. Refresh tokens rotate; replay revokes the token family and grant. Narrowing refresh scopes also narrows the grant, so later refreshes cannot regain removed permissions. Revocation accepts refresh tokens and prevents future refreshes; it does not immediately invalidate existing access JWTs.