Skip to content

Authentication

Type Who Lifetime Where used
Session cookie Users (dashboard) 7 days absolute, 30 min sliding idle Browser
API key Users (CLI, scripts) No expiry; revocable Authorization: Bearer z4k_...
Agent token + HMAC secret Agents No expiry; revocable WebSocket handshake (token) + frame signing (HMAC secret)
POST /api/v1/auth/login
Content-Type: application/json
{ "email": "...", "password": "..." }

Response sets z4j_session=...; HttpOnly; Secure; SameSite=Lax. Subsequent requests send the cookie automatically. The session is rejected after Z4J_SESSION_ABSOLUTE_LIFETIME_SECONDS (default 604800 = 7 days) or after Z4J_SESSION_IDLE_TIMEOUT_SECONDS (default 1800 = 30 minutes) of inactivity, whichever fires first.

POST /api/v1/auth/logout

Invalidates the session server-side.

Endpoint Purpose
GET /api/v1/auth/me Current user + project memberships.
PATCH /api/v1/auth/me Update display name etc.
POST /api/v1/auth/change-password Authenticated password change.
GET /api/v1/auth/sessions List the user’s active sessions.
POST /api/v1/auth/sessions/{session_id}/revoke Revoke a single session.
POST /api/v1/auth/password-reset/request # public; body: {"email": "..."}
POST /api/v1/auth/password-reset/confirm # public; body: {"token": "...", "password": "..."}

The reset token TTL is 30 minutes. The request endpoint never reveals whether the email exists – it returns success either way.

Create from Dashboard, Settings, API keys. Tokens begin with z4k_ and are shown once at creation.

Terminal window
curl -H "Authorization: Bearer z4k_..." \
https://z4j.example.com/api/v1/projects/billing-prod/tasks

Management endpoints:

Endpoint Purpose
GET /api/v1/api-keys List the caller’s keys (prefix + scopes only; plaintext never re-emitted).
POST /api/v1/api-keys Mint a new key. Response carries the plaintext once.
DELETE /api/v1/api-keys/{key_id} Revoke a key.
GET /api/v1/api-keys/scopes Catalog of valid scopes.

API keys can be project-scoped (bound to one project’s slug at mint time) or unscoped. A project-scoped key automatically filters GET /projects to that one project and is rejected on cross-project paths.

Minted via the agents APIPOST /api/v1/projects/{slug}/agents returns both a bearer token (WebSocket handshake) and an hmac_secret (per-frame signing). Agents refuse to start without the HMAC secret.

Rate limits on auth (per IP, 1-minute window)

Section titled “Rate limits on auth (per IP, 1-minute window)”
Endpoint Cap
POST /auth/login 20 hits / minute
POST /auth/password-reset/request and /confirm 10 hits / minute (combined bucket)
GET /invitations/preview and POST /invitations/accept 30 hits / minute (combined bucket)

Per-account lockout runs in parallel with the per-IP login cap: repeated wrong passwords on a single account lock that account for a cooling-off window regardless of source IP. See security rate limits for the design rationale.

Multi-factor authentication is built in: a TOTP second factor from any standard authenticator app, ten single-use recovery codes, and an opt-in remember-this-device cookie. Sensitive actions require a fresh second-factor step-up. Org-wide enforcement is available and off by default, with a per-user grace window. See multi-factor authentication and MFA enforcement.

Not currently shipped. The recommended interim approach is to put z4j behind an authenticated reverse proxy (oauth2-proxy, Cloudflare Access, Pomerium) so the SSO layer authenticates the user before they reach z4j’s login form.