Auth API Reference
Timbl auth is adapter-driven. Core routes are stable, but principal shape,
provider cookies, provider redirects, and action bodies are owned by the
runtime AuthAdapter. If an app does not configure one, the timbl runtime
installs a default Better Auth adapter.
The generated OpenAPI document at GET /openapi.json includes auth endpoints,
standard security schemes, and per-operation security requirements. The Scalar
docs UI renders those schemes so protected requests can be authorized directly
from /docs.
OpenAPI / Scalar Security
The generated spec defines two generic auth schemes:
| Scheme | Type | Applies to |
|---|---|---|
sessionCookie | apiKey in cookie session | Cookie/session based adapters. The concrete cookie name may vary by provider. |
bearerAuth | HTTP bearer | Token based adapters that resolve Authorization: Bearer <token>. |
Protected content routes declare both schemes as alternatives. Public auth routes, such as session lookup and auth actions, declare auth as optional so Scalar can send credentials when an action needs them (for example sign-out) without making sign-in impossible.
Timbl always emits baseline canonical action paths. Scalar therefore shows stable action routes such as:
POST /api/cms/auth/actions/loginPOST /api/cms/auth/actions/registerPOST /api/cms/auth/actions/logoutThose routes all use the same Timbl runtime handler and call
AuthAdapter.invoke(action, body, authContext). The default Better Auth adapter
implements login, register, and logout; custom adapters can override those
actions or add their own. A custom adapter that omits invoke still returns
501 NOT_IMPLEMENTED for auth actions.
Capabilities
AuthAdapter.getCapabilities() returns AuthCapabilities, including:
provider: string identifier (e.g.better-auth)providerRoutes:{ enabled: boolean; basePath?: string }— when enabled, the adapter may handle provider HTTP traffic (Better Auth defaults to/api/auth)actions: optional map of stable action names to descriptions plus Zod input/output schemas. Timbl always includeslogin,register, andlogout, then merges adapter-provided actions on top so adapters can refine schemas or add more concrete action routes.- feature flags such as
supportsAnonymous,supportsOrganizations,supportsImpersonation, andsupportsServiceAccounts
GET /api/cms/auth/session
Returns whether the current request has a resolved principal, plus serialized principal and identity when authenticated.
This route is public and safe to call without credentials.
200 response
{ "authenticated": true, "principal": { "id": "user_123", "email": "editor@example.com" }, "identity": { "provider": "better-auth", "subject": "user_123", "sessionId": "session_123", "actorType": "human", "expiresAt": "2026-05-12T12:00:00.000Z" }}Unauthenticated response:
{ "authenticated": false, "principal": null, "identity": null}POST /api/cms/auth/actions/:action
Invokes adapter.invoke(action, body, authContext). The default Better Auth
adapter implements the canonical actions. Custom adapters without invoke
return 501 NOT_IMPLEMENTED.
The parsed JSON body (or form-derived object) is passed as the second argument to invoke—use whatever shape your adapter expects (e.g. flat fields or a nested input property by convention).
The login, register, and logout paths are always shown in /openapi.json
and Scalar. Adapters should implement those names when they apply, and can
advertise additional names through AuthCapabilities.actions. The generic
:action path remains available for custom or unadvertised actions.
Common examples:
POST /api/cms/auth/actions/loginContent-Type: application/json
{ "email": "editor@example.com", "password": "correct horse battery staple"}POST /api/cms/auth/actions/registerContent-Type: application/json
{ "name": "Editor", "email": "editor@example.com", "password": "correct horse battery staple"}POST /api/cms/auth/actions/logoutCookie: session=...
{}Responses
- Determined by the adapter (
status, optionalheaders,body/principalhandling in the runtime handler) 400for invalid request bodies401when the adapter action requires a session and none is present501when a custom adapter does not implementinvoke(NOT_IMPLEMENTED)
Provider passthrough routes
Adapters with capabilities.providerRoutes.enabled and handleRequest() are
mounted under their provider base path. The default Better Auth adapter uses:
/api/auth/*The generated OpenAPI document represents that catch-all as
/api/auth/{path} so Scalar exposes the provider route family without
pretending Timbl owns each provider-specific request or response shape.
Better Auth
Install @timbl/adapter-better-auth and pass an invoke implementation that maps action to Better Auth API calls. See Better Auth adapter.