Skip to content

Recipes

Gate a tool behind a scope

import { assertScope, verifyPassport } from 'agent-passport';

const passport = await verifyPassport(passportJwt);

function guarded<T extends (...a: any[]) => any>(scope: string, fn: T): T {
  return (async (...args: Parameters<T>) => {
    assertScope(passport, scope); // throws if not granted
    return fn(...args);
  }) as T;
}

const sendEmail = guarded('email:send', rawSendEmail);

Build a tamper-evident audit trail

import { signAction, verifyAction } from 'agent-passport';

async function withAudit(agent, type: string, target: string, run: () => Promise<unknown>) {
  const result = await run();
  const proof = await signAction(agent, { type, target });
  await auditStore.append({ proof, at: new Date().toISOString() });
  return result;
}

// later, prove who did it:
const { agent } = await verifyAction(savedProof);

Verify the full trust chain

import { verifyPassport, verifyAction, hasScope } from 'agent-passport';

async function trust(actionJwt: string, passportJwt: string, trustedOperators: Set<string>) {
  const action = await verifyAction(actionJwt);
  const passport = await verifyPassport(passportJwt);
  return (
    passport.agent.id === action.agent &&               // passport is about this agent
    trustedOperators.has(passport.operator) &&           // operator is trusted
    hasScope(passport, action.action.type)               // scope covers the action
  );
}

Short-lived passports (rotation)

// re-issue daily; did:key has no revocation, so keep windows small
await issuePassport({ operator, agentDid: agent.did, name: 'bot', scopes: ['crm:read'], expiresIn: 86400 });