Authorization for agent actions · MIT

Authorize the action.
Not the agent.

Enforce user-aware policy at the tool boundary, resolve credentials at execution time, and keep tamper-evident proof — open-source, framework-neutral core.

prompt-injected agent · one deny rule

$ agent reads an email — injected instructions inside

model obeys: email.forward → [email protected]

BLOCKED before the tool ran — deny:email.forward (exfiltration)

? email.delete? held for a human — denied

§ every decision sealed on the receipt chain

chain verifies — doctored log detected

the model was compromised. the policy didn't care.

Works with the stack you already run

Run it yourself — no API keys, no network

An injected agent tries to exfiltrate your data. Policy says no.

The tools are wrapped with nominee.guard(). The model obeys the injection anyway — models do — and the deny rule fires before the tool runs. Every attempt, allowed or refused, is sealed into a signed, tamper-evident receipt chain. One command:

$ node run.mjs

2. the model obeys the injection and tries to exfiltrate

BLOCKED before the tool ran — deny:email.forward (exfiltration)

5. the receipt chain (signed, tamper-evident)

  #0 policy.decision email.read     allow  5493c2c54cd5

  #1 policy.decision email.forward  deny   ca6a069febdb

  #2 policy.decision email.delete   ask    d2fe628a5202

  #4 approval.resolved email.delete denied 2b0ac4aa3ad8

  #5 policy.decision email.forward  allow  fd17436d92c0

chain verifies: 6 receipts intact

doctored log detected — broken at #1

Tokens, the supporting act — settled live

Same agent. One outlives its token.

Two agents call a protected API across a session longer than the token lives (~8s here). Left grabs a token once and reuses it. Right calls nominee.run() so the strategy resolves a fresh token at execution time. The real nominee package runs in your browser — open the Network tab and watch the refresh.

starting…
captured token grab once, reuse forever — what every orchestrator leaves you to do
nominee nominee.run() — fresh token at execution time

Start on your DB → Auth0 → Nango. Your agent code never changes — only the strategy line does. The Passport.js of agent auth, scoped to the no-lock-in tail:

agent.ts
const nominee = new Nominee({
  strategy: ({ user, connection }) => db.refreshToken(user, connection), // zero signup
})
// everything below is identical, whatever the strategy ↓
const token = await nominee.token({ user, connection: 'github' })

The race above runs the oauth2 line. Want the auth0 line for real? → watch a live agent act on your GitHub, after your approval.

How it works

Checked as the user. Bound to the call. On the record.

Your framework controls the run and approval UI. nominee enforces the application decision underneath it: who is acting, what exact input was authorized, which credential the tool receives, and what evidence remains.

A prompt-injected agent tries to exfiltrate the inbox; nominee's deny rule blocks the tool call before it runs, holds the delete for a human, and seals a signed receipt of every decision.
  • User-aware policy on every call

    Declarative allow / deny / ask rules see the user, tool, arguments, and delegation chain. Async predicates can consult your existing RBAC, FGA, OPA, or application policy.

  • Exact-call enforcement

    Policy and approval bind to the user, tenant, resource, exact arguments, policy version, and a single-use execution capability. Credentials arrive only after capability consumption.

  • §

    On the register

    Every decision, approval, capability, credential grant, and outcome is a hash-chained, optionally signed receipt. Mutated records and gaps break verification; externally anchored stream tips expose rollback.

Install and go

Keep your framework. Keep your IAM. Enforce them at the tool boundary.

Start with ordered allow / deny / ask rules, then connect async predicates and token strategies to the authorization and credential systems you already run.

agent.ts
import { Nominee, allow, deny, ask } from 'nominee'

// native approvals control the run; nominee enforces application policy:
const nominee = new Nominee({
  policy: [
    allow('email.read'),
    deny('email.forward', { reason: 'exfiltration' }),
    ask('email.delete'), // a human decides, every time
  ],
})

// one line — every call checked before the tool runs
const tools = nominee.guard({ 'email.read': readEmail, 'email.forward': forwardEmail }, { user: 'alice' })

Decision-bound capability

Approve once. Execute exactly that action.

An ask rule holds deletes, payments, or outbound mail for human review. When a framework pauses your tool run, Nominee enforces the underlying boundary: binding the approval to the exact input, generating a single-use execution capability, re-checking resource permission, and fetching fresh credentials only once the capability is consumed.

Awaiting countersignature

repo.delete

Delete repository alice/old-project

DenyApprove
you → triage-bot → github · on the register

Where nominee sits

A thin, neutral seam — not another platform.

Your framework should run the agent and its approval UI. nominee enforces the application decision underneath: whether this user may take this exact action on this tenant's resource, which authority reaches execution, and what evidence remains.

When you don't need nominee

  • A read-only agent with no authority worth guarding.
  • Your platform's native permission system covers you end-to-end and you're happy inside it.
  • You want one fully-managed vendor for tools + auth + policy — use Arcade or Composio directly.

Reach for nominee when the action must inherit the real user's resource permissions, broad credentials must move behind the boundary, or several runtimes need one enforcement and evidence contract.

Packages

One authorization layer, wherever your agent runs.

Core

nominee

Policy engine, approvals, hash-chained receipts, token brokering. Zero runtime deps.

Vercel AI SDK

nominee-ai

guardTools wraps your AI SDK tools in one line; nomineeTool for per-tool config. Runs on Cloudflare Agents too.

Vercel Eve

nominee-eve

Policy enforcement, portable approvals, and fresh tokens inside Eve tools.

Optional · Strategy

nominee-supabase

Store provider tokens in Supabase; nominee reads and refreshes them. Zero deps.

Optional · Managed

nominee-auth0

Auth0 Token Vault for federated tokens, and CIBA approvals on the user's phone.

Production storage

nominee-postgres

Transactional actions, budgets, single-use capabilities, outcomes, journals, and receipt streams.

OpenAI Agents SDK

nominee-openai

Decision-bound tools with Nominee ask rules mapped to native resumable approvals.

Mastra

nominee-mastra

Mastra tools with native or portable durable approval and execution-time credentials.

Model Context Protocol

nominee-mcp

Register guarded tools on the official MCP server SDK with durable pending handles.

FAQ

The questions people actually ask.

Isn't this just an if-statement with extra steps?

For one low-risk tool, an if-statement may be enough. nominee is useful when the decision must use the real user and resource, stay bound to exact arguments, narrow delegated authority, control credential delivery, and produce one evidence stream across runtimes.

Can the model talk its way past a deny?

No. The model never sees the policy — it only ever gets the tools you handed it via nominee.guard(). A deny rule throws PolicyDeniedError inside the wrapper, before your tool's own code runs. There's no prompt for the model to argue with; the call physically doesn't happen.

Do receipts store my data?

Not by default. Tool inputs are recorded as inputHash — a SHA-256 of the canonical JSON — so you can prove what an approver saw without writing user data into the log. Pass receipts: { input: 'raw' } if you want the full input on the record instead, or 'none' to skip it entirely.

Can receipts be forged?

Tamper-evident, not non-repudiation — say that plainly. Without a signing key, the chain is publicly re-computable: anyone can verify it wasn't edited, but anyone with write access to the whole log could also rewrite it consistently. Pass an HMAC key and only key-holders can produce valid hashes — that's the guarantee to reach for once receipts leave your own process.

How is this different from Arcade, Composio, or Vercel Connect?

Those products can manage connections and tools. nominee is the open-source enforcement layer that binds your application policy to the exact tool action. It can use a managed platform, your IAM, or your own token store underneath.

Does nominee replace my auth provider (Auth0, Clerk, WorkOS)?

No — authentication (who is the user) is a separate, solved problem. nominee is the layer above it, deciding what an already-authenticated agent may do as that user. It composes with whatever you already use; Auth0 is one optional strategy among several, not a requirement.

What happens if I don't configure a policy?

Everything is allowed — and still receipted. nominee doesn't restrict anything until you add rules, so you can adopt it incrementally: wrap your tools first, watch the receipt chain to see what your agent actually does, then tighten the policy once you know.

When don't I need nominee?

A read-only agent with no authority worth guarding. Your platform's native permission system already covers you end-to-end. Or you want one fully-managed vendor for tools, auth, and policy together — use Arcade or Composio directly.

Give your agent a nominee.

Open source, MIT, zero-dependency core. It works the moment you install it.

★ Star on GitHub

▶ Watch a real agent act on your GitHub, after your approval →

GitHub stars npm version npm downloads license