Skip to main content

Quickstart

Ninka is an authorization compiler. You write authorization as a declarative Tegata (手形), compile it to Rego/WASM, and enforce it through a typed check(). This guide takes you from an empty project to your first authorization decision. For the ideas behind it, see Authorization Compiler.

1. Install

npm install ninka-authz

Node.js 20 or later. The package bundles the ninka CLI and the runtime.

2. Scaffold

npx ninka init

Creates the authz/ workspace, a lib/authz.ts boundary, and an AGENTS.md. See the CLI reference.

3. Write a Tegata

One policy per authz/<policy-id>.tegata.json. Start with a single rule:

{
"tegata": "0.1",
"policy": { "id": "invoice-access", "description": "Invoice access" },
"rules": [
{
"id": "allow-employee-view-invoice",
"effect": "allow",
"subject": { "roles": ["employee"] },
"actions": ["view"],
"resource": { "type": "invoice" }
}
]
}

An employee may view an invoice. See Tegata and the Tegata Schema.

4. Compile

npx ninka compile

Runs the Sekisho checks and emits Rego, WASM, and typed TypeScript to authz/out/. See Generated Files.

5. Verify

npx ninka verify

The CI gate: recompiles and requires byte-identity with the committed authz/out/. Run it on every pull request.

6. Enforce in your app

ninka init generated lib/authz.ts. Call check() from your handler:

import { check, policies } from "@/lib/authz";

const allowed = await check(policies.invoiceAccess, {
subject: { properties: { roles: session.user.roles, user_id: session.user.id } },
action: { name: "view" },
resource: { type: "invoice", properties: { amount: invoice.amount, submitted_by: invoice.submittedBy } },
});
if (!allowed) {
return new Response("Forbidden", { status: 403 });
}
  • check() returns a boolean — true to proceed, false to reject.
  • The policy is named explicitly through the typed policies table.
  • The input shape is enforced by the generated types.

For Ninka.load, decision logs, and options, see the Runtime API.