Skip to main content

Authentication and session model

Orbit recognizes three credential classes: dv_-prefixed API keys, dashboard session tokens, and the SCIM provisioning token. Each request carries one of them, and a single resolution rule decides the class from the headers you send. This page defines the vocabulary, states the rule, and tells you which credential each audience (server, dashboard, identity provider) should send. For route-by-route rejection codes, see the authentication troubleshooting page.

Section 1 — The credential vocabulary

Three credential classes authenticate to Orbit. They look different on the wire, authorize different surfaces, and get managed in different places. API keys (dv_ prefix). Long-lived credentials you create in the dashboard under Settings → API Keys and use for programmatic calls. Four forms exist: A public key (pk) is meant for browser or mobile bundles, so the platform rejects write and administrative scopes on it at creation with a 422. For anything that sends or modifies data — messages:write, contacts:write, admin, the * wildcard — use a secret key (sk). Dashboard session token (JWT). A signed JSON Web Token issued when a dashboard user signs in — email/password, or SAML single sign-on where enabled. Session tokens carry a user’s identity and the org memberships they belong to; they authenticate the person, not an application. You recognize one by the eyJ prefix that every JWT starts with. SCIM provisioning token. A dedicated Bearer credential that authenticates exactly one surface: the /scim/v2/{orgSlug} endpoints your identity provider calls to create and remove dashboard users. It is neither an API key nor a session token, and it is valid on no other route.

Section 2 — How resolution is decided

The server determines which credential class a request carries with one precedence rule:
  1. A non-empty X-API-Key header is checked first.
  2. Only if X-API-Key is absent does the server look at Authorization: Bearer, and only when the token carries a dv_ prefix is it treated as an API key.
  3. Any other Bearer token — the eyJ… JWT shape — is treated as a dashboard session token.
Because a JWT always starts with eyJ and every API key starts with dv_, the two forms never collide on the Authorization header. This is the fallback rule stated on the authentication page, and it exists so browser environments where the X-API-Key custom header is blocked by CORS can still send an API key as a Bearer token. The practical consequence: sending both an X-API-Key header and a session Bearer is unambiguous — the API key wins. A malformed request mixes the two only when the client generated it wrong; the resolution rule still makes the outcome deterministic.

Section 3 — Session token lifecycle

A dashboard session token moves through four states:
  1. Issued at login. Email/password sign-in, or the SAML callback from your identity provider when SSO is configured, both mint a signed JWT.
  2. Used until expiry. The dashboard sends it on every API request as an Authorization: Bearer eyJ… header. Session tokens have bounded lifetimes; an expired token gets a 401.
  3. Rotated. Re-authentication or a token refresh issues a replacement JWT; the old one expires on its own schedule.
  4. Terminated on sign-out. Signing out invalidates the token; the next request with it fails.
This lifecycle is why the SSO pages assume a session credential exists: SAML single sign-on and SCIM provisioning are dashboard-side concerns. SAML mints session tokens at login; SCIM manages the users who hold them. Neither touches API keys — server-to-server integrations keep using dv_ keys while users come and go through the IdP.

Section 4 — The SCIM provisioning token

Generate the token under Settings → SCIM in the dashboard, or with POST /api/v1/settings/scim/generate-token. The full value is shown once at creation — copy it into your IdP immediately; if you lose it, generate a new one. The endpoint is a dashboard-session-authorized call, so minting or rotating the token requires a signed-in administrator. Your IdP then sends the token as a Bearer credential against the SCIM resource endpoints (/scim/v2/{orgSlug}/Users, /Groups), which return application/scim+json. The step-by-step IdP walkthroughs for Okta, Entra ID, and generic clients are in the SCIM 2.0 provisioning guide (and the tenant-owned posture view in compliance). Because the value is shown once, treat rotation as “generate a new token, update the IdP, discard the old” — a one-step operation, but one you must plan for when you do not retain the original.

Section 5 — Where tenant identity comes from

The credential is also how the platform learns which tenant a request belongs to. Every org is a row in the shared organizations catalog; each API key is issued against exactly one org, and the server resolves the key back to that org on every request. A dashboard session token likewise carries its org bound at login and selected from the user’s memberships. Client-supplied claims of tenant identity (tenant_id fields in a request body) are never trusted. The full resolution chain — catalog lookup, tenant_<tenant_id> schema routing, and the subaccount sharing rules — is covered in Tenant isolation.

Section 6 — What to branch on

Send the credential class that matches the caller’s relationship to the platform: When you build on an SDK, set the same choice: the SDK sends either an API key or a session token; the resolution rule above applies untouched. Two rules of thumb close out most mistakes:
  • A 401 means the credential did not resolve. A truncated key, a dv_ value sent as Authorization: Bearer without the full prefix, or a session token whose expiry has passed all fail here.
  • A 422 from SSO or SCIM usually means you sent a session surface an API key (or vice versa). Match the credential class to the table above, then re-check the scopes page for sk vs pk if the route still rejects.