Ceiba Docs

Getting Started

Quickstart

Protect an existing Express or Fastify route with the Ceiba Node SDK. The SDK extracts the downstream API key, calls Runtime, and either attaches normalized access context or returns a stable denial response.

Before You Start

You need:

  • an existing Node API using Express or Fastify
  • a Ceiba Runtime URL
  • an owner-scoped project created in the Control Plane
  • the project ID shown on the Control Plane Overview
  • the project secret shown once during project creation or rotation
  • an active downstream API key
  • an active access policy matching the route and method you will protect

The three SDK settings stay on your API server:

CEIBA_RUNTIME_URL=<your-runtime-url>
CEIBA_PROJECT_ID=<your-project-id>
CEIBA_PROJECT_SECRET=<your-project-secret>

Never expose CEIBA_PROJECT_SECRET in browser or mobile code. It authenticates your backend to Runtime and is separate from the downstream API key presented by callers.

For project setup, see the Control Plane Operator Guide. For rotation, see Project Secret Rotation.

Install The SDK

npm install @ceibalabs/ceiba-sdk

The package source is available in the Ceiba Node SDK repository.

Configure The Runtime Client

import {
  CeibaRuntimeClient,
  parseCeibaSdkConfig,
} from "@ceibalabs/ceiba-sdk";
 
const config = parseCeibaSdkConfig({
  runtimeBaseUrl: process.env.CEIBA_RUNTIME_URL!,
  projectId: process.env.CEIBA_PROJECT_ID!,
  projectSecret: process.env.CEIBA_PROJECT_SECRET!,
});
 
const client = new CeibaRuntimeClient(config);

Runtime remains the source of truth for project auth, API-key validation, policy matching, subscription gating, quotas, rate limits, and usage recording.

Protect An Express Route

Use ceibaExpressMiddleware on the route you want Runtime to evaluate:

import express from "express";
import {
  CeibaRuntimeClient,
  parseCeibaSdkConfig,
} from "@ceibalabs/ceiba-sdk";
import { ceibaExpressMiddleware } from "@ceibalabs/ceiba-sdk/express";
 
const config = parseCeibaSdkConfig({
  runtimeBaseUrl: process.env.CEIBA_RUNTIME_URL!,
  projectId: process.env.CEIBA_PROJECT_ID!,
  projectSecret: process.env.CEIBA_PROJECT_SECRET!,
});
 
const client = new CeibaRuntimeClient(config);
const app = express();
 
app.get(
  "/v1/hello",
  ceibaExpressMiddleware(client, config.projectId),
  (req, res) => {
    res.json({ ok: true, ceibaAccess: req.ceibaAccess });
  },
);

After an allow decision, normalized context is available as req.ceibaAccess.

See the runnable Express proof.

Protect A Fastify Route

Use ceibaFastifyPreHandler as a route-level pre-handler:

import Fastify from "fastify";
import {
  CeibaRuntimeClient,
  parseCeibaSdkConfig,
} from "@ceibalabs/ceiba-sdk";
import { ceibaFastifyPreHandler } from "@ceibalabs/ceiba-sdk/fastify";
 
const config = parseCeibaSdkConfig({
  runtimeBaseUrl: process.env.CEIBA_RUNTIME_URL!,
  projectId: process.env.CEIBA_PROJECT_ID!,
  projectSecret: process.env.CEIBA_PROJECT_SECRET!,
});
 
const client = new CeibaRuntimeClient(config);
const app = Fastify();
 
app.get(
  "/v1/hello",
  {
    preHandler: ceibaFastifyPreHandler({
      client,
      projectId: config.projectId,
    }),
  },
  async (request) => {
    return { ok: true, ceibaAccess: request.ceibaAccess };
  },
);

After an allow decision, normalized context is available as request.ceibaAccess.

See the runnable Fastify proof.

Call The Protected Route

The Express and Fastify adapters accept either a bearer token or x-api-key:

curl -i \
  -H "Authorization: Bearer <downstream-api-key>" \
  http://localhost:3000/v1/hello
curl -i \
  -H "x-api-key: <downstream-api-key>" \
  http://localhost:3000/v1/hello

Denial Mapping

Runtime returns a normalized denialReason. The shipped adapters map it as follows:

Runtime denialHTTP statusResponse error
missing_api_key, invalid_api_key, revoked_api_key, archived_api_key, expired_api_key401ceiba_unauthorized
policy_no_match, inactive_subscription403ceiba_forbidden
quota_exceeded429ceiba_quota_exceeded
rate_limited429ceiba_rate_limited

Transport Mapping

Project-secret failures, malformed Runtime input, and service failures are transport errors rather than downstream access denials.

Runtime transport statusHost API status
401 or 403503
400502
500 and abovePreserved
Any other non-success status502

Direct client users can use:

  • httpStatusForDenial
  • ceibaErrorCodeForDenial
  • httpStatusForRuntimeTransport
  • CeibaRuntimeTransportError

These helpers provide response mapping only. Enforcement remains in Runtime.

Next Steps

GoalGuide
Create projects, keys, policies, and subscriptionsControl Plane Operator Guide
Rotate the server-side project secretProject Secret Rotation
Create and retire API keys from your backendProgrammatic API Keys