Skip to content

Authentication

The Centrali SDK supports three authentication methods. Choose the right one based on your use case.

Workspace slug terminology

The SDK still uses the option name workspaceId, but the value you pass is your workspace slug such as acme-corp, not an internal UUID.

Which method should I use?

Scenario Method SDK Option
Frontend app (React, Vue, public) Publishable key publishableKey
Frontend with user login (Clerk, Auth0) External token getToken
Third-party app acting as a user OAuth (auth code + PKCE) getToken
Third-party app with scoped machine access OAuth (client credentials) getToken
Server-side script or backend (policy-based auth) Service account clientId + clientSecret

Publishable Keys

Publishable keys are scoped, browser-safe credentials for frontend apps. They bypass workspace policies — only the key's scopes determine what it can access.

Create a publishable key in the console, select which collections, triggers, and files it can access, then use it in your app:

import { CentraliSDK } from '@centrali-io/centrali-sdk';

const centrali = new CentraliSDK({
  baseUrl: 'https://centrali.io',
  workspaceId: 'my-workspace', // current SDK option name; pass the workspace slug
  publishableKey: 'pk_live_a1b2c3d4e5f6g7h8',
});

// Read records (if scoped)
const posts = await centrali.queryRecords('posts');

// Submit a form (if scoped)
await centrali.createRecord('contact-submissions', {
  name: 'Jane',
  message: 'Hello!',
});

Key characteristics:

  • Sent as x-api-key header (not Bearer token)
  • No token refresh needed — the key is static
  • Scopes follow resource:action:target format (e.g., records:list:posts)
  • Wildcard targets (*) only allowed for read actions
  • Admin resources (users, groups, policies) are never accessible
  • Rate limited per key: 200 reads/min, 30 writes/min

Security: Publishable keys are safe to expose in client-side code. They are workspace-scoped and can only access the specific resources their scopes allow.

External Tokens (BYOT)

If your app has its own authentication (Clerk, Auth0, Okta, etc.), use the getToken callback to pass your provider's JWT to Centrali:

const centrali = new CentraliSDK({
  baseUrl: 'https://centrali.io',
  workspaceId: 'my-workspace', // current SDK option name; pass the workspace slug
  getToken: async () => {
    // Get a fresh token from your auth provider
    return await clerk.session.getToken();
  },
});

// Full access governed by Centrali policies
await centrali.updateRecord('posts', 'post-123', { title: 'Updated' });

Key characteristics:

  • Token is sent as Authorization: Bearer header
  • getToken is called before each request to ensure a fresh token
  • On 401, the SDK retries once with a new token from getToken
  • Access is governed by Centrali policies and group membership (workspace policies, roles, groups apply)
  • Requires an external auth provider configured in the console

You can also pass a static token directly:

const centrali = new CentraliSDK({
  baseUrl: 'https://centrali.io',
  workspaceId: 'my-workspace', // current SDK option name; pass the workspace slug
  token: 'eyJhbGciOiJSUzI1NiIs...',
});

OAuth Apps

OAuth apps let third-party applications access Centrali on behalf of a user or as a machine identity. Create an OAuth app in Console > Settings > OAuth Apps, select scopes, and choose a grant type.

OAuth Scopes (Client Credentials)

For server-to-server integrations where no user is involved. The app authenticates with its own credentials and receives scoped access:

const centrali = new CentraliSDK({
  baseUrl: 'https://centrali.io',
  workspaceId: 'my-workspace', // current SDK option name; pass the workspace slug
  getToken: async () => {
    // Exchange client credentials for an access token
    const resp = await fetch('https://auth.centrali.io/oauth/token', {
      method: 'POST',
      headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
      body: new URLSearchParams({
        grant_type: 'client_credentials',
        client_id: process.env.OAUTH_CLIENT_ID,
        client_secret: process.env.OAUTH_CLIENT_SECRET,
      }),
    });
    const data = await resp.json();
    return data.access_token;
  },
});

OAuth Authorization Code + PKCE (User Login)

For browser apps, CLI tools, or AI agents that need to act as a specific user. The user logs in via a browser and approves access:

  1. Redirect the user to the authorization endpoint
  2. User logs in and approves the requested scopes
  3. Your app receives an authorization code at the redirect URI
  4. Exchange the code (+ PKCE verifier) for access and refresh tokens
GET https://auth.centrali.io/oauth/authorize?
  response_type=code&
  client_id=oc_your_client_id&
  redirect_uri=http://localhost:3000/callback&
  scope=records:read records:list&
  state=random-csrf-state&
  code_challenge=BASE64URL(SHA256(code_verifier))&
  code_challenge_method=S256

After the user approves, exchange the code:

POST https://auth.centrali.io/oauth/token
  grant_type=authorization_code
  code=AUTHORIZATION_CODE
  redirect_uri=http://localhost:3000/callback
  client_id=oc_your_client_id
  code_verifier=YOUR_CODE_VERIFIER

Response:

{
  "access_token": "eyJ...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "ort_...",
  "scope": "records:read records:list"
}

Key characteristics:

  • Tokens carry the user's identity (sub = user ID, not client ID)
  • Access governed by OAuth scopes — only approved permissions are granted
  • Refresh tokens rotate on each use (old token is invalidated)
  • Consent is remembered — returning users skip the approval screen
  • PKCE is required for public clients, optional for confidential clients
  • Only S256 challenge method is supported

Available Scopes

Scope Description
records:read Read records
records:write Create, update, delete records
records:list List records
structures:read Read collection definitions
structures:list List collections
queries:read Read smart queries
queries:write Create, update, delete queries
queries:list List smart queries
queries:execute Execute smart queries
files:read Read and download files
files:write Upload, update, delete files
files:list List files
folders:read Read folder details
folders:write Create, update, delete folders
folders:list List folders
compute:read Read function definitions
compute:write Create, update, delete functions
compute:list List functions
compute:execute Execute functions
orchestrations:read Read orchestrations
orchestrations:write Create, update, delete orchestrations
orchestrations:list List orchestrations
orchestrations:execute Trigger orchestration runs
search:read Search entries
pages:read Read pages
pages:write Create, update, delete pages
pages:list List pages
workspace:read Read workspace information

Client Types

Type Secret Use Case
Confidential Has a client secret Server-side apps, backend services
Public No secret (PKCE required) Browser apps, CLIs, native apps, MCP

Service Accounts

Service accounts use OIDC client credentials for server-to-server authentication with Centrali policy-based permissions (roles, groups, policies). Never use client secrets in browser code.

const centrali = new CentraliSDK({
  baseUrl: 'https://centrali.io',
  workspaceId: 'my-workspace', // current SDK option name; pass the workspace slug
  clientId: process.env.CENTRALI_CLIENT_ID,
  clientSecret: process.env.CENTRALI_CLIENT_SECRET,
});

// Full access governed by Centrali policies
await centrali.deleteRecord('posts', 'post-123');

Key characteristics:

  • Token is fetched automatically via client credentials grant on first request
  • On 401/403, the SDK refreshes the token and retries once
  • Access is governed by Centrali policies and group membership
  • Create service accounts in the console, then follow the service account guide

Mutual Exclusion

Only one auth method can be used at a time. The SDK throws an error if conflicting options are provided:

// This throws: "Cannot use publishableKey with clientId/clientSecret"
new CentraliSDK({
  publishableKey: 'pk_live_...',
  clientId: 'ci_...',
  clientSecret: 'sk_...',
});

Publishable Keys vs Centrali Policies

Publishable keys and Centrali policies are separate authorization systems:

Publishable Keys Centrali Policies
Used by publishableKey auth path token, getToken, clientId/clientSecret
Authorization Scopes embedded in the key Policies evaluated by IAM
Managed in Console Console
Granularity resource:action:target Conditions (time, IP, claims, groups)
Admin access Never Policy-dependent

If you need conditional access (time-based, IP-restricted, group-based), use Centrali policies with user tokens or service accounts. If you need simple, scoped frontend access, use publishable keys.