Auth Model
The Chainabit API uses JWT-based authentication. Human users usually arrive through the web UI or the device flow, while non-interactive clients should use time-bounded developer tokens and exchange them for a normal token pair.
Token Pair
A successful login returns two tokens:
| Token | Purpose | Typical Lifetime |
|---|---|---|
| Access Token | Authenticates API requests via the Authorization header | 1 hour |
| Refresh Token | Obtains a new access token without re-entering credentials | Longer-lived |
Access tokens are short-lived for security. When an access token expires, the client uses the refresh token to obtain a new pair without prompting the user to log in again.
Browser Session Flow
Making Authenticated Requests
Include the access token in the Authorization header using the Bearer scheme:
GET /api/v1/ai/sessions HTTP/1.1
Host: {your-api-host}
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...If the token is missing, expired, or invalid, the API returns 401 Unauthorized.
Captcha-Protected Endpoints
Certain sensitive endpoints require a captcha token (Cloudflare Turnstile) in addition to any other authentication. This prevents automated abuse of high-risk operations.
The following endpoints require captcha verification:
| Endpoint | Description |
|---|---|
POST /auth/register | Account registration |
POST /auth/login | Login |
POST /auth/forgot-password | Password reset request |
POST /auth/resend-confirmation | Resend email confirmation |
To pass captcha verification, include the Turnstile token in the x-captcha-token request header:
POST /api/v1/auth/login HTTP/1.1
Content-Type: application/json
x-captcha-token: 0.AbCdEfGh...
{
"email": "[email protected]",
"password": "your-password"
}The Turnstile token is obtained client-side by rendering the Cloudflare Turnstile widget. See the Cloudflare Turnstile documentation for integration details.
Token Refresh
When an access token expires, call the refresh endpoint with your refresh token:
POST /api/v1/auth/refresh HTTP/1.1
Content-Type: application/json
{
"refreshToken": "your-refresh-token"
}The response returns a new token pair. Store both tokens securely and replace the old ones.
CLI And Automation Flows
Interactive CLI: Device Authorization
The browser session approves the CLI request, but the browser tokens never need to be copied into the CLI. Approval is a separate protected API call and the CLI only receives its own session payload once approved.
Non-Interactive CLI And Apps: Developer Tokens
Developer tokens are opaque, time-bounded, and stored server-side as hashes. They are the recommended way to authenticate scripts and CI jobs.
Best Practices
- Store tokens securely. Never expose tokens in URLs, local storage (for web apps), or client-side logs.
- Prefer developer tokens for automation. Avoid sending account passwords to CLI or CI jobs when a developer token can be used instead.
- Implement automatic refresh. When you receive a 401 response, attempt a token refresh before prompting the user to log in again.
- Handle refresh failures gracefully. If the refresh token is also expired or revoked, redirect the user to the login flow.
- Do not hardcode tokens. Use environment variables or secure vaults for server-to-server integrations.
OAuth Authentication
OAuth allows users to sign in using a third-party identity provider (Google, GitHub, Microsoft) without creating a separate password.
The flow uses PKCE (S256) — the API generates a code verifier and challenge for every initiation, stores the flow state, and verifies the state parameter on callback to prevent CSRF.
Identity resolution priority:
- Linking flow — user is already authenticated and linking a new provider
- Existing identity — a record for this provider + provider ID already exists
- Email match — email is verified and matches an existing account (auto-link)
- New user — create a new account with the provider identity
Magic Link (Passwordless)
Magic link is a passwordless authentication method where the user receives a time-limited, single-use login link by email.
- Tokens are SHA-256 hashed before storage (raw token never stored)
- Links expire after 10 minutes
- Token is deleted on first use (single-use)
- The send endpoint always returns
{ status: "ok" }regardless of whether the email exists (anti-enumeration)
Device Flow Details
Device codes expire after the TTL returned in expiresIn. User codes are formatted as XXXX-XXXX with visually unambiguous characters (no I, O, 0, 1). Approval requires an authenticated browser session and the approval API should log the event without ever logging raw device or access tokens.
Enterprise API Keys
Enterprise accounts can create account-scoped API keys for service-to-service integrations and automated pipelines. Unlike developer tokens (which are personal and require a session exchange), enterprise API keys authenticate directly as bearer tokens.
| Developer Tokens | Enterprise API Keys | |
|---|---|---|
| Format | cbt_live_* | chb_sk_* |
| Scope | Personal (you) | Account-wide |
| Auth model | Direct bearer on supported endpoints; legacy exchange remains temporarily available | Direct bearer |
| Best for | CLI, personal automation, CI jobs | M2M, integrations, account-level services |
Creating an API Key
Enterprise API keys are managed by account owners and admins:
POST /api/v1/accounts/{accountId}/api-keys
Authorization: Bearer <your-jwt>
Content-Type: application/json
{
"name": "Production Pipeline Key",
"scopes": ["contexts:read", "agents:execute"],
"expiresInDays": 90
}The raw key (chb_sk_*) is returned once only in the response. Store it immediately in a secure vault.
Using an API Key
Send the key as a bearer token:
GET /api/v1/...
Authorization: Bearer chb_sk_<your-key>Revoking a Key
DELETE /api/v1/accounts/{accountId}/api-keys/{keyId}
Authorization: Bearer <your-jwt>Available Scopes
| Scope | Access |
|---|---|
contexts:read | Read knowledge contexts and semantic search |
contexts:write | Create and update knowledge contexts |
agents:read | Read agent definitions |
agents:execute | Execute agent tools and sessions |
analytics:read | Analytics and audit data |
members:read | Read account and workspace members |
Enterprise RBAC
Enterprise accounts use a two-level role model, checked by role alone -- there is no separate per-action permission grant to layer on top.
Account Roles (assigned when a member is added or an invitation is accepted, changeable afterward by an owner or admin):
owner— full control. Not assignable through the member or invitation endpoints; ownership transfer is a dedicated flow.admin— full control except ownership transfermember— standard accessanalyst— read-only analyticsbilling— billing management onlyviewer— read-only
Workspace Roles (set per workspace):
owner,admin,member,analyst,billing,viewer
Account owners and admins automatically inherit access to all workspaces without needing an explicit workspace membership row.
Bringing someone into an account happens one of two ways: POST /accounts/:accountId/members attaches a chainer who already has an account by their user ID directly; Account Invitations sends a link to an email address and creates the membership only once it's accepted. Both assign a role from the list above at the same point the membership is created.