Authentication
Authentication methods supported by ctx| — email/password, OAuth, passkeys, two-factor, and device authorisation.
ctx| uses Better Auth for identity management.
All auth endpoints are served under /.auth/api/v1/auth/.
Email and password
Standard credential-based sign-in. Password reset emails are sent via the configured SMTP provider.
Sign up
POST /.auth/api/v1/auth/sign-up/email
Content-Type: application/json
{
"email": "[email protected]",
"password": "...",
"name": "Your Name"
}Sign in
POST /.auth/api/v1/auth/sign-in/email
Content-Type: application/json
{
"email": "[email protected]",
"password": "..."
}Password reset
Trigger a reset email:
POST /.auth/api/v1/auth/forget-password
Content-Type: application/json
{ "email": "[email protected]" }Social providers (OAuth)
ctx| supports GitHub, Google, and Microsoft OAuth out of the box. Each provider is enabled conditionally — if the corresponding client ID and secret are set in the backend environment, the sign-in option appears.
| Provider | Env vars required |
|---|---|
| GitHub | GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET |
GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET | |
| Microsoft | MICROSOFT_CLIENT_ID, MICROSOFT_CLIENT_SECRET |
Initiate flow
GET /.auth/api/v1/auth/sign-in/<github|google|microsoft>?callbackURL=/dashboardThe user is redirected to the provider, then back to callbackURL on completion.
On first sign-in via any method, ctx| automatically creates a personal organisation and sets it as the active org on the session. No separate onboarding step is required.
Passkeys (WebAuthn)
Passkeys are supported for passwordless sign-in on supporting platforms. Registration and assertion follow the WebAuthn Level 2 spec.
POST /.auth/api/v1/auth/passkey/register
POST /.auth/api/v1/auth/passkey/authenticateThe Better Auth passkey plugin documentation covers the full client-side integration.
Two-factor authentication (TOTP)
2FA is available to all users via any TOTP-compatible authenticator app.
Enable 2FA
POST /.auth/api/v1/auth/two-factor/enableReturns a TOTP secret and a QR code URL. The user scans this with their authenticator app and confirms with a valid OTP to activate.
Verify on sign-in
When 2FA is enabled, a second request is required after credential verification:
POST /.auth/api/v1/auth/two-factor/verify
Content-Type: application/json
{ "code": "123456" }Session model
Successful authentication returns a session cookie. Sessions are stored in
Postgres and tracked in the sessions table. Each session carries an
activeOrganizationId which determines the organisation context for all
subsequent requests.
To switch the active organisation (for users who are members of multiple orgs), use the organisation API — see Managing your organisation.
Bearer tokens and API keys
For programmatic access (MCP, CI pipelines, scripts), use API keys rather than
session cookies. Keys are issued as short-lived JWTs backed by the bearer plugin.
Generate a key from the dashboard under Settings → API Keys, then pass it as:
Authorization: Bearer <key>See ctx| MCP for the full connection configuration.
OAuth provider (for downstream clients)
ctx| is itself an OAuth 2.0 authorisation server, meaning third-party applications can request access tokens on behalf of users. The authorisation server supports:
- Dynamic client registration (no manual approval step)
- OpenID Connect discovery (
/.well-known/openid-configuration) - Device Authorization Grant for headless clients
- JWT access tokens with
ctx| base URLand/mcpas valid audiences
This is the mechanism used when an MCP client authenticates using OAuth rather than a static API key.
Trusted origins
In production, set AUTH_ALLOWED_ORIGINS to a comma-separated list of allowed
origins for CSRF protection. In development, localhost origins are trusted by default.