Skip to content

How Authentication Works

Centrali uses OAuth 2.0 for authentication and Resource-Based Access Control (ReBAC) for authorization. All access decisions are workspace-scoped.

Authentication Methods

Use for: API integrations, SDK usage, server-to-server communication, CI/CD pipelines, production deployments.

  1. Create a service account in your workspace dashboard
  2. Receive client_id and client_secret
  3. Exchange credentials for a JWT access token
  4. Use the token in API requests

This is the primary authentication method for building with Centrali.

2. User Authentication (Dashboard Login)

Use for: Accessing the Centrali web dashboard and interactive administration.

  • Login at centrali.io via email/password or social login (Google, GitHub)
  • Session managed automatically via browser cookies

3. External Authentication (BYOT)

Use for: Applications that use their own identity provider (Clerk, Auth0, Okta).

Centrali validates your external JWT tokens and maps claims to its authorization system. See External Auth (BYOT) for details.


Service Account Authentication Flow

Step 1: Create a Service Account

See the Account Setup Guide for detailed instructions.

You'll receive:

client_id: ci_a1b2c3d4e5f6g7h8i9j0
client_secret: sk_0123456789abcdef...

Step 2: Obtain an Access Token

Exchange your credentials for a JWT token:

Endpoint: POST https://auth.centrali.io/oidc/token

curl -X POST "https://auth.centrali.io/oidc/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials" \
  -d "client_id=ci_a1b2c3d4e5f6g7h8i9j0" \
  -d "client_secret=sk_0123456789abcdef..." \
  -d "scope=openid"

Response:

{
  "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "Bearer",
  "expires_in": 25200,
  "scope": "openid"
}

Token Details: - Lifetime: 7 hours (25,200 seconds) - Type: JWT (JSON Web Token) - Refresh: Request a new token before expiration

Step 3: Use the Token

Include the token in the Authorization header:

curl -X GET "https://api.centrali.io/data/workspace/my-workspace/api/v1/structures" \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."

The Centrali SDK handles token management automatically:

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

const centrali = new CentraliSDK({
  baseUrl: 'https://api.centrali.io',
  workspaceId: 'my-workspace',
  clientId: process.env.CENTRALI_CLIENT_ID,
  clientSecret: process.env.CENTRALI_CLIENT_SECRET
});

// SDK automatically fetches, caches, and refreshes tokens
const products = await centrali.queryRecords('Product', { limit: 10 });

How Authorization Works

Centrali uses a three-tier authorization model:

Request → Resource Lookup → Permission Matching → Policy Evaluation → Allow/Deny

Resources

Resources represent protected entities (e.g., records, structures, files). Each resource defines allowed actions like create, retrieve, update, delete, list.

Policies

Policies contain rules that determine access. They use conditions to check attributes like group membership, roles, user identity, IP address, and time of day.

Permissions

Permissions connect resources to policies. They specify which actions on a resource are governed by which policy, and at what priority.

For detailed reference on creating custom resources, policies, and permissions, see Policies & Permissions.


Groups and Roles

Access is controlled through groups and roles, not fixed permission strings.

Groups

Groups are collections of users and/or service accounts. Policies reference groups in their conditions. Default groups include:

  • workspace_owners — Full access
  • workspace_administrators — Broad management access

You can create custom groups for any access pattern (e.g., developers, viewers, api-users).

Roles

Roles are named labels assigned to users and service accounts within a workspace. Default roles include:

  • workspace_owners — Cannot be deleted; identifies workspace owners

How Permissions Flow

User / Service Account
  Assigned to Groups & Roles
  Policies check group/role membership
  Permissions link policies to resources + actions
  Access Allowed or Denied

Example: To give a group read-only access to records:

  1. Create a group (e.g., readonly-users)
  2. Create a policy that allows access when the user is in readonly-users
  3. Create a permission linking the records resource to that policy for retrieve and list actions
  4. Add users to the readonly-users group

Service Account Access

Service accounts get their permissions through group membership, exactly like users.

  1. Create a service account in the dashboard or via API
  2. Create or select a group with the appropriate policies
  3. Add the service account to the group
  4. The service account inherits all permissions granted to that group

Full Admin Access

To give a service account full workspace access, add it to the workspace_administrators group.


Security Best Practices

Storing Credentials

  • Use environment variables or secret management services
  • Never hardcode in source code or commit to version control
  • Use different credentials per environment

Credential Rotation

  • Development: Rotate every 90 days
  • Production: Rotate every 30-90 days
  • Immediately if credentials are compromised

Token Management

  • Cache tokens until near expiration (refresh 5 minutes early)
  • Use the SDK for automatic token lifecycle management
  • Handle 401 errors with re-authentication

Common Authentication Patterns

Backend API Service

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

const centrali = new CentraliSDK({
  baseUrl: 'https://api.centrali.io',
  workspaceId: process.env.CENTRALI_WORKSPACE,
  clientId: process.env.CENTRALI_CLIENT_ID,
  clientSecret: process.env.CENTRALI_CLIENT_SECRET
});

app.get('/api/products', async (req, res) => {
  const products = await centrali.queryRecords('Product', {
    filter: { inStock: true },
    limit: 20
  });
  res.json(products);
});

Serverless Function (Vercel, AWS Lambda)

// api/products.js
import { CentraliSDK } from '@centrali-io/centrali-sdk';

// Initialize outside handler for connection reuse
const centrali = new CentraliSDK({
  baseUrl: 'https://api.centrali.io',
  workspaceId: process.env.CENTRALI_WORKSPACE,
  clientId: process.env.CENTRALI_CLIENT_ID,
  clientSecret: process.env.CENTRALI_CLIENT_SECRET
});

export default async function handler(req, res) {
  const products = await centrali.queryRecords('Product', { limit: 10 });
  res.json(products);
}

JWT Token Claims

Service account tokens include these claims:

{
  "sub": "ci_a1b2c3d4e5f6g7h8i9j0",
  "iss": "https://auth.centrali.io",
  "aud": "https://api.centrali.io",
  "iat": 1705326000,
  "exp": 1705351200,
  "workspace": "my-workspace",
  "isServiceAccount": "true",
  "groups": ["developers"],
  "roles": ["workspace_owners"]
}

Troubleshooting

"Invalid client credentials"

  • Verify credentials in dashboard
  • Check for whitespace in environment variables
  • Ensure you're using the correct workspace's credentials

"Token expired"

  • Tokens expire after 7 hours — fetch a new one
  • Use the SDK for automatic token refresh
  • Check system clock synchronization

"Forbidden" or "Unauthorized"

  • Verify workspace slug matches token
  • Check Authorization: Bearer {token} header format
  • Ensure the service account's group has the required permissions

See the Troubleshooting Guide for more help.