Skip to main content
CoreSDK
SDK Reference

TypeScript SDK Reference

Complete API reference for the @coresdk/sdk package

Phase 2 — not yet available. The TypeScript SDK ships in Phase 2. The API documented below reflects the planned design.

TypeScript SDK Reference

Complete API reference for @coresdk/sdk. For a working example, see the TypeScript Quickstart.

npm install @coresdk/sdk
# or
pnpm add @coresdk/sdk
# Phase 2 — not yet published

Node.js 18+ and TypeScript 5+ required.


new CoreSDK(options)

Creates and configures a CoreSDK instance. JWKS are fetched lazily on the first authenticated request.

Signature

new CoreSDK(options: CoreSDKOptions): CoreSDK

CoreSDKOptions

interface CoreSDKOptions {
  tenant: string;
  jwksUrl: string;
  policyDir?: string;           // default: "./policies"
  otelEndpoint?: string;
  tokenHeader?: string;         // default: "Authorization"
  clockSkew?: number;           // seconds, default: 30
  errorMapper?: ErrorMapper;
}
OptionTypeRequiredDescription
tenantstringYesTenant identifier for this service instance
jwksUrlstringYesURL of the JWKS endpoint used to verify JWTs
policyDirstringNoDirectory of .rego policy files. Defaults to "./policies"
otelEndpointstringNoOTLP gRPC endpoint for traces and metrics
tokenHeaderstringNoHTTP header carrying the bearer token. Defaults to "Authorization"
clockSkewnumberNoAcceptable JWT clock skew in seconds. Defaults to 30
errorMapperErrorMapperNoCustom error response handler (see Error types)

Example

import { CoreSDK } from "@coresdk/sdk";

const sdk = new CoreSDK({
  tenant: "acme",
  jwksUrl: "https://your-idp.com/.well-known/jwks.json",
  policyDir: "./policies",
  otelEndpoint: "http://localhost:4317",
});

CoreSDKMiddleware

Returns an Express-compatible RequestHandler that authenticates every request, populates req.user and req.tenant, and emits OTEL spans.

Signature

middleware(): RequestHandler

Returns RequestHandler (compatible with Express 4/5 and Connect)

Usage

import express from "express";
import { CoreSDK } from "@coresdk/sdk";

const sdk = new CoreSDK({ tenant: "acme", jwksUrl: "..." });
const app = express();

app.use(CoreSDKMiddleware);

app.get("/api/orders", (req, res) => {
  // req.user is CoreSDKUser, req.tenant is CoreSDKTenant
  res.json({ userId: req.user.id });
});

Unauthenticated requests receive 401. Policy-blocked requests receive 403. Both return RFC 9457 application/problem+json.


require_role(action)

Returns an Express middleware that enforces a policy action check. Apply it per-route after CoreSDKMiddleware.

Signature

require(action: string): RequestHandler

Parameters

ParameterTypeDescription
actionstringPolicy action string, e.g. "orders:read"

Returns RequestHandler

Usage

app.get(
  "/api/orders",
  require_role("orders:read"),
  async (req, res) => {
    const orders = await db.orders.forUser(req.user.id);
    res.json(orders);
  }
);

app.post(
  "/api/orders",
  require_role("orders:write"),
  async (req, res) => {
    const order = await db.orders.create(req.body, req.user.id);
    res.status(201).json(order);
  }
);

sdk.currentUser(req)

Retrieves the authenticated user from an Express request object. Returns null if no user was attached (i.e., middleware was not applied).

Signature

currentUser(req: Request): CoreSDKUser | null

Returns CoreSDKUser | null

import { Request } from "express";

function auditAction(req: Request, action: string) {
  const user = sdk.currentUser(req);
  if (!user) throw new Error("unauthenticated");
  auditLog.write({ userId: user.id, tenantId: user.tenantId, action });
}

Fastify plugin

import Fastify from "fastify";
import { coreSDKPlugin } from "@coresdk/sdk/fastify";

const fastify = Fastify();

await fastify.register(coreSDKPlugin, {
  tenant: "acme",
  jwksUrl: "https://your-idp.com/.well-known/jwks.json",
});

fastify.get("/api/orders", {
  preHandler: fastify.corerequire_role("orders:read"),
  handler: async (request) => {
    // request.user is CoreSDKUser
    return db.orders.forUser(request.user.id);
  },
});

The plugin decorates the Fastify instance with fastify.coresdk and each request with request.user and request.tenant.


Next.js App Router

// app/api/orders/route.ts
import { withCoreSDK } from "@coresdk/sdk/next";

export const GET = withCoreSDK(
  { action: "orders:read" },
  async (req, { user, tenant }) => {
    const orders = await db.orders.forUser(user.id);
    return Response.json(orders);
  }
);

export const POST = withCoreSDK(
  { action: "orders:write" },
  async (req, { user }) => {
    const body = await req.json();
    const order = await db.orders.create(body, user.id);
    return Response.json(order, { status: 201 });
  }
);

withCoreSDK options

OptionTypeDescription
actionstringPolicy action to require. Omit to authenticate only, without an action check

sdk.policy().evaluate(rule, input)

Evaluates an OPA policy rule directly, outside the middleware path.

Signature

evaluate(rule: string, input: Record<string, unknown>): Promise<PolicyResult>

Parameters

ParameterTypeDescription
rulestringDot-separated Rego rule path, e.g. "data.billing.can_upgrade"
inputRecord<string, unknown>Input document passed to the policy engine

Returns Promise<PolicyResult>

interface PolicyResult {
  allowed: boolean;
  reason?: string;
}

Usage

const result = await sdk.policy().evaluate("data.billing.can_upgrade", {
  user: req.user,
  targetPlan: "enterprise",
});

if (!result.allowed) {
  res.status(403).json({ error: result.reason ?? "Upgrade not permitted" });
  return;
}

Tenant management

All tenant methods return Promise<T>.

sdk.tenants.get(id)

get(id: string): Promise<CoreSDKTenant>
const tenant = await sdk.tenants.get("acme");
console.log(tenant.plan);

sdk.tenants.create(options)

create(options: CreateTenantOptions): Promise<CoreSDKTenant>

interface CreateTenantOptions {
  id: string;
  name: string;
  plan?: TenantPlan;              // defaults to "free"
  metadata?: Record<string, unknown>;
}
const tenant = await sdk.tenants.create({
  id: "newcorp",
  name: "New Corp",
  plan: "business",
});

sdk.tenants.update(id, options)

update(id: string, options: UpdateTenantOptions): Promise<CoreSDKTenant>

interface UpdateTenantOptions {
  name?: string;
  plan?: TenantPlan;
  metadata?: Record<string, unknown>;
}
const tenant = await sdk.tenants.update("newcorp", { plan: "enterprise" });

sdk.tenants.delete(id)

delete(id: string): Promise<void>
await sdk.tenants.delete("oldcorp");

sdk.tenants.list()

list(): Promise<CoreSDKTenant[]>
const tenants = await sdk.tenants.list();
tenants.forEach(t => console.log(t.id, t.plan));

TypeScript types

All types are exported from @coresdk/sdk.

import type {
  CoreSDKUser,
  CoreSDKTenant,
  TenantPlan,
  PolicyResult,
  CoreSDKOptions,
  CreateTenantOptions,
  UpdateTenantOptions,
  ErrorMapper,
} from "@coresdk/sdk";

CoreSDKUser

interface CoreSDKUser {
  id: string;                          // JWT sub claim
  email: string;                       // JWT email claim
  role: string;                        // Mapped role for this tenant
  tenantId: string;                    // Tenant the user belongs to
  rawClaims: Record<string, unknown>;  // Full decoded JWT claims
}

CoreSDKTenant

interface CoreSDKTenant {
  id: string;
  name: string;
  plan: TenantPlan;
  metadata: Record<string, unknown>;
}

type TenantPlan = "free" | "team" | "business" | "enterprise";

Express augmentation

@coresdk/sdk ships global augmentations for Express so req.user and req.tenant are typed automatically — no import needed in handler files.

// Automatically available when @coresdk/sdk is installed:
declare global {
  namespace Express {
    interface Request {
      user: CoreSDKUser;
      tenant: CoreSDKTenant;
    }
  }
}

Error types

All SDK methods throw subclasses of CoreSDKError.

import {
  CoreSDKError,
  TokenExpiredError,
  TokenInvalidError,
  PolicyDeniedError,
  TenantNotFoundError,
  JwksFetchError,
  ConfigurationError,
} from "@coresdk/sdk/errors";
ClassPropertiesDescription
TokenExpiredErrorexpiredAt: DateJWT exp claim is in the past
TokenInvalidErrorreason: stringBad signature, malformed JWT, or missing required claims
PolicyDeniedErroraction: string, reason?: stringOPA policy returned false
TenantNotFoundErrortenantId: stringTenant lookup returned no record
JwksFetchErrorurl: string, cause: unknownNetwork or parse failure fetching JWKS
ConfigurationErrormessage: stringMissing required option or invalid value

Handling errors

import { PolicyDeniedError, TokenExpiredError } from "@coresdk/sdk/errors";

try {
  const user = sdk.currentUser(req);
} catch (err) {
  if (err instanceof TokenExpiredError) {
    console.log("Expired at", err.expiredAt);
  } else if (err instanceof PolicyDeniedError) {
    console.log(`Denied: ${err.action} — ${err.reason}`);
  }
}

Custom ErrorMapper

import { ErrorMapper, CoreSDKError, PolicyDeniedError } from "@coresdk/sdk/errors";
import { Response } from "express";

class MyMapper implements ErrorMapper {
  map(err: CoreSDKError, res: Response): void {
    if (err instanceof PolicyDeniedError) {
      res.status(403).json({
        type: "https://errors.acme.com/forbidden",
        title: "Action not permitted",
        detail: `'${err.action}' is not allowed`,
      });
    } else {
      this.default(err, res);
    }
  }
}

const sdk = new CoreSDK({
  tenant: "acme",
  jwksUrl: "https://your-idp.com/.well-known/jwks.json",
  errorMapper: new MyMapper(),
});

On this page