Skip to content

Authentication

oikapi uses session-based authentication with secure cookies.

POST /api/auth/login
Content-Type: application/json
{
"identifier": "user@example.com",
"password": "Pass123!"
}

Sets a session cookie and returns {"user": {...}}. All subsequent browser requests use the cookie for authentication. Native (non-browser) clients additionally receive a session_token in the response body, which they may send as Authorization: Bearer <session_token>.

The identifier field accepts either an email address or a handle — an identifier containing @ is treated as an email, otherwise as a handle. This lets organizations that don’t use email addresses log users in by handle. (The older email field is still accepted.)

If your account has a second factor (an authenticator app or a passkey), login returns an mfa_required challenge instead of a session; complete it at POST /api/auth/mfa/verify.

Oikapi supports WebAuthn/FIDO2 passkeys. A passwordless passkey login is phishing-resistant and needs no second step:

POST /api/auth/webauthn/login/begin → { "ceremony_id", "options" }
POST /api/auth/webauthn/login/finish → { "user": {...} } + session

Hand options to navigator.credentials.get() and post the result to /finish. You can register additional passkeys on your account via POST /api/auth/webauthn/register/begin and /finish.

POST /api/auth/register
Content-Type: application/json
{
"email": "user@example.com",
"password": "Pass123!",
"name": "Jane Smith"
}

Password requirements: at least one uppercase, one lowercase, one number, and one special character. The minimum length defaults to 8 characters and is admin-configurable (via the security.password_min_length setting) up to 72.

GET /api/auth/me

Returns the authenticated user’s profile.

POST /api/auth/logout

Destroys the current session.

Auth endpoints are always rate-limited regardless of global rate limiting configuration:

EndpointLimit
POST /api/auth/login5 per minute per IP
POST /api/auth/register3 per minute per IP
POST /api/auth/forgot-password5 per hour per IP
POST /api/auth/reset-password5 per hour per IP
GET /api/auth/verify-email10 per hour per IP
POST /api/auth/resend-verification10 per hour per IP

The email-verification and resend-verification limits are configurable via the rate_limiting.auth.email_verification_per_hour setting (default 10).

After 5 failed login attempts within 15 minutes, the account is temporarily locked. The lockout duration starts at 15 minutes and doubles with each subsequent lockout (capped at 24 hours). A successful login resets the lockout counter.

Lockout responses return HTTP 429 with a retry_after value in seconds.

Sessions auto-renew on each request. There is no manual refresh endpoint.

SettingDefaultDescription
security.session.lifetime168hMaximum session duration
security.session.idle_timeout8hTimeout after inactivity
security.session.cookie_same_siteLaxCookie SameSite policy. Lax, not Strict — this instance is also an OpenID Provider, and Strict withholds the session cookie on the cross-site navigation to /oauth/authorize, silently breaking silent SSO for relying parties on a different registrable domain.

For programmatic access, use API keys instead of sessions. Pass the key with the ApiKey authorization scheme:

GET /api/apps/myapp/tables/projects/records
Authorization: ApiKey <api-key>

API keys are managed as records on the api_keys system table:

POST /api/apps/system/tables/api_keys/records
GET /api/apps/system/tables/api_keys/records
DELETE /api/apps/system/tables/api_keys/records/{id}

The raw key value is returned only once, at creation time. API keys inherit the permissions of the user they’re created for.

Oikapi does not require every user to have an email address. Organizations can identify users by handle instead, in which case the traditional “verify by email” and “reset password by email” links don’t apply. For those accounts, first-time credential setup and account recovery run through a one-time setup token rather than an email link:

POST /api/auth/setup/password { "token": "...", "password": "..." }
POST /api/auth/setup/passkey/begin { "token": "..." } # → drives a passkey registration

Setting up a password also returns one-time recovery codes — save them; they let you regain access offline if you lose your credential.

If your account has a phone number on file and your organization has enabled it, you can recover access via a one-time SMS code:

POST /api/auth/recover/sms/begin { "identifier": "<email or handle>" }
POST /api/auth/recover/sms/verify { "identifier": "<email or handle>", "code": "123456" }

verify returns a setup token you exchange at /api/auth/setup/password or /api/auth/setup/passkey/begin. SMS recovery is off by default and must be enabled by an administrator. For security, begin always returns a generic success response and never reveals whether an account or phone number exists.