ScalixScalix Docs
Sign up

Authentication

API keys explained properly: the key types and their prefixes, project-scoped keys, scopes, restrictions, expiry and rotation, connected apps, and end-user app auth

Overview

Every request to api.scalix.world carries a key in the Authorization header:

bash
curl -H "Authorization: Bearer $SCALIX_API_KEY" \
  https://api.scalix.world/v1/functions

Keys are created in the console at Org → API Keys. The full key is shown once, at creation. After that the console only shows its prefix, so store it somewhere real when you create it.

Key types and prefixes

The prefix on a key tells you what it is. There are five:

Console namePrefixMade forScopes
Secret Keyscalix_sk_Server-side apps and SDKsThe scopes you select
Service Accountscalix_sa_CI/CD pipelinesThe scopes you select
Full Access Keyscalix_at_Getting started, trusted automationEvery data-plane scope, fixed
Personal Access Tokenscalix_pat_The CLI and personal toolingThe scopes you select
Publishable Keyscalix_pk_Browser bundles (end-user auth bootstrap)None, by design

Two of these behave differently from the rest, and it is worth knowing why:

  • A Full Access Key (scalix_at_) always carries every data-plane scope. The server enforces this at creation, so the type label always matches what the key can really do. It cannot carry platform scopes (admin:full and similar), and you cannot trim it down. If you want fewer permissions, use a Secret Key.
  • A Publishable Key (scalix_pk_) carries no scopes at all and never can. It exists to identify your project to the public /v1/auth/* routes from client-side code. On any other route the gateway rejects it. Safe to ship in a browser bundle; useless to an attacker who lifts it.

Project-scoped keys

A key is either org-wide or pinned to a single project, chosen at creation. Pin it.

Most of the platform acts within a project: databases, functions, storage, Run services, Computers. A project-scoped key matches that shape, and it keeps the blast radius of a leak to one project instead of your whole organization. A client's production app, for example, should run on its own project with its own key, not share one with everything else you operate.

Two rules that follow from how permissions work:

  • Only Owners and Admins can create org-wide keys. Members with project restrictions must pick a project.
  • Key management is for humans. Creating, rotating, and revoking keys requires a signed-in user session; an API key cannot mint, rotate, or revoke keys — not even keys weaker than itself. (A key can also never mint a key more powerful than its creator: the new key's scopes must be a subset of what the caller holds.)

Org-wide keys and X-Scalix-Project

Several surfaces refuse an org-wide key outright unless the request names a project: Storage, the container registry, databases, Functions, Shield, Prime analytics, and MCP. The error reads this operation requires a project-scoped API key (or names the service).

An org-wide key names the project per request:

bash
curl -H "Authorization: Bearer $SCALIX_API_KEY" \
     -H "X-Scalix-Project: <project-uuid>" \
     https://api.scalix.world/v1/storage/buckets

The CLI --project flag and the SDK project option send the same header, and IAM only honors it when the project belongs to the key's org. A project-bound key needs none of this — it is locked to its project.

Scopes

There are 64 named scopes. They follow a service:action pattern; the ones you will meet first:

ScopeGrants
database:readSELECT/SHOW/EXPLAIN only — true read-only SQL
database:queryRun SQL against your databases (includes writes; legacy behavior)
database:branchCreate and manage database branches
storage:read / storage:writeRead and write objects
functions:deploy / functions:invoke / functions:logsDeploy, call, and inspect functions
services:deploy / services:read / services:logsManage Scalix Run services
compute:deploy / compute:scale / compute:logsContainer workloads
ai:infer / ai:modelsAI inference and the model catalog
kv:read / kv:writeKey-value store
events:publish / events:readPub/Sub
registry:pull / registry:pushContainer registry
search:readScalix Search
metering:readYour own usage data

The console's key form shows the complete list with a description for each. Select the scopes the workload needs and no more; a dozen well-chosen scopes covers most production services.

When a request is refused: a 401 means the key itself was not accepted (wrong, revoked, or expired). A 403 means the key is real but lacks a scope the route requires, or it is a publishable key on a scoped route. The gateway's error strings are literal, and each maps to one fix:

ErrorFix
this operation requires a project-scoped API keyBind a project at key creation, or send X-Scalix-Project (above)
storage API requires a project-scoped API keySame — Storage always needs the project named
publishable keys cannot be used for resource operationsscalix_pk_ keys are auth-bootstrap only; use a server-side key for the API
key is read-only — only SELECT, SHOW, and EXPLAIN are allowedThe key was created with Read-Only enabled; use a non-read-only key for writes
missing scope: database:read or database:queryAdd the database scope the route needs
key management requires a signed-in user sessionCreate/rotate/revoke keys from the console while signed in, not with an API key

Restrictions at creation

Three optional restrictions can be attached to any key:

  • Read-only (console toggle): the key can never mutate state. The gateway default-denies POST/PUT/PATCH/DELETE across the whole API — with a small allow-list for endpoints that legitimately read via POST (SQL queries, search, AI inference, DB advice endpoints). On the SQL plane only SELECT/SHOW/EXPLAIN pass, and the Postgres session itself is set read-only as a second layer.
  • IP allowlist (API field ip_allowlist, CIDR entries): requests from any other address are refused, fail-closed.
  • Require approval (API field require_approval): high-risk operations from this key pause until a human approves them — the agent cannot approve its own request. Every connected app (below) gets this automatically.

Connected apps (OAuth grants)

Third-party clients — ChatGPT, Claude, an IDE — connect through OAuth, not hand-minted keys. When a user approves the consent screen, Scalix mints an scalix_oat_ grant token:

  • It counts against the org's connected-apps quota, not the raw API-key quota, and can be revoked by app name.
  • It carries exactly the scopes shown on the consent screen — nothing broader.
  • It expires on a fixed TTL and always requires human approval for high-risk operations.

Connected apps are managed in the console under Org → API Keys → Approvals, alongside approval requests.

Expiry and rotation

Keys default to a 90-day expiry unless you choose a different period or No expiration at creation. The console's API Keys page shows each key's last-used time. A key showing Never or a stale date is your first candidate for revocation.

Rotation mints a replacement and keeps the old secret working for a grace window (24 hours by default) so deployed services can swap without downtime. Revocation is immediate and permanent. If a key has leaked, revoke it, do not rotate it: rotation's grace window keeps the leaked secret alive.

CLI login

bash
scalix-cloud login

The CLI prompts for a key, validates it against the API, and stores it in the OS keychain on macOS and Windows, or an owner-only (0600) ~/.scalix/token file on Linux. It is never written to ~/.scalix/config.toml.

Any key type that validates works here: a Personal Access Token is the intended fit, but a Secret Key or Full Access Key logs in the same way. You can also pass the key directly: scalix-cloud login scalix_pat_your_key_here.

Environment Variables

The CLI reads these environment variables (the SDKs take the API key as an explicit constructor argument):

VariableDescription
SCALIX_TOKENAPI key the CLI uses for authentication
SCALIX_API_URLAPI endpoint (default: https://api.scalix.world)

App authentication (your end users)

Everything above is about your access to the platform. For signing up and logging in your application's users, use the auth SDK against your project:

typescript
import { ScalixAuthClient } from "@scalix-world/auth";
 
const auth = new ScalixAuthClient({
  url: "https://api.scalix.world",
});
 
// Sign up a new user
const { user, session } = await auth.signUp("user@example.com", "secure-password");
 
// Sign in
const result = await auth.signInWithPassword("user@example.com", "secure-password");
 
// MFA enrollment
const factor = await auth.enrollMfa("totp", "My Phone");

The publishable key (scalix_pk_) is what identifies your project to these routes from the browser. End-user sessions are JWTs scoped to your application; they cannot touch the platform API.