Skip to content

personal-access-tokens

Long-lived, revocable Personal Access Tokens for headless HTTP-API access. Stores SHA-256 token hashes in the read_api_tokens direct-write table; the plaintext is returned once at creation. create/revoke/mine manage a user’s own tokens and available-scopes lists the app-declared scope catalog. Bearer tokens carrying the PAT prefix are resolved before jwt.verify (roles resolved live, granted scopes enforced fail-closed at the API boundary) — the resolver is wired via run-prod-app, not the dispatcher. Pass { toggleable: { default: false } } to tier-gate the whole feature.

From apps-use-all-bundled — the smallest working mount:

// Smoke-entrypoint for use-all-bundled. CI runs this with
// KUMIKO_DRY_RUN_ENV=boot to exercise validators across every bundled
// feature without an actual postgres/redis. See package.json `boot`
// script + ../README.md.
import { frameworkCoreEnvSchema, runProdApp } from "@cosmicdrift/kumiko-dev-server";
import { InMemoryKmsAdapter } from "@cosmicdrift/kumiko-framework/crypto";
import type { TenantId } from "@cosmicdrift/kumiko-framework/engine";
import { composeEnvSchema } from "@cosmicdrift/kumiko-framework/env";
import { APP_FEATURES } from "../src/run-config";
const SMOKE_TENANT_ID = "00000000-0000-4000-8000-000000000001" as TenantId;
const envSchema = composeEnvSchema({
core: frameworkCoreEnvSchema,
features: APP_FEATURES,
});
await runProdApp({
features: APP_FEATURES,
envSchema,
// Smoke-only: exercises the hard PII boot gate + blind-index gate with
// every bundled feature mounted. Real apps wire createPgKmsAdapter(...).
kms: new InMemoryKmsAdapter(),
blindIndexKey: Buffer.alloc(32, 7).toString("base64"),
// migrations default ("./kumiko/migrations") — Boot-mode springt vor dem
// Schema-Drift-Gate raus, der Pfad ist hier nur der runProdApp-Default.
// auth.admin triggert composeFeatures(includeBundled:true) — auto-mounts
// config + user + tenant + auth-email-password. Boot-mode exitiert
// bevor admin-Seeding läuft, der Wert ist nur ein Stub für die Typen.
auth: {
admin: {
password: "smoke-only-never-deployed",
displayName: "Smoke Admin",
memberships: [
{
tenantId: SMOKE_TENANT_ID,
tenantKey: "smoke",
tenantName: "Use-All-Bundled Smoke",
roles: ["TenantAdmin"],
},
],
},
},
});

📄 On GitHub: samples/apps/use-all-bundled/bin/main.ts

What this feature needs to run (Requires, top) and the write commands it provides (Provides, bottom).

flowchart TB
  n_personal_access_tokens["personal-access-tokens"]
  subgraph how_reqs["Requires"]
    n_user["user"]
    n_tenant["tenant"]
  end
  subgraph how_provides["Provides"]
    n_cmd_personal_access_tokens_write_create(["create"])
    n_cmd_personal_access_tokens_write_revoke(["revoke"])
  end
  n_user --> n_personal_access_tokens
  n_tenant --> n_personal_access_tokens
  n_personal_access_tokens --> n_cmd_personal_access_tokens_write_create
  n_personal_access_tokens --> n_cmd_personal_access_tokens_write_revoke

Provides — write commands this feature registers (dispatch them through the command bus):

Start with apps-use-all-bundled for a step-by-step walkthrough with runnable code and integration tests.

  • Requires: user, tenant
  • Activation: always on (not toggleable)