Skip to main content
Authorization is the core of what Veto does. Every time your AI agent is about to call a tool, you check with Veto first. Veto evaluates the request against the agent’s policies and tells you whether to proceed.

The authorization flow

1

Agent requests a tool call

Your AI agent decides it wants to call a tool — for example, file.write with a specific path.
2

You call veto.authorize()

Before executing the tool, your code calls veto.authorize() with the agent ID, tool name, and parameters.
3

Veto evaluates policies

Veto retrieves the agent’s enabled policies, sorts them by priority, and evaluates each one in order until a decision is reached.
4

You receive allow or deny

Veto returns an AuthorizationResult. If allowed is true, you proceed. If false, you block the action.

Calling authorize()

const result = await veto.authorize("agent-uuid", "file.write", { path: "/etc/passwd" });

if (!result.allowed) {
  console.log(result.reason); // "Tool 'file.write' parameter 'path' violates constraint"
}
The third argument — parameters — is optional but important. Pass the actual parameters the agent is using so that parameter_constraint rules can be evaluated correctly.
Always pass the full parameter object to authorize(). A parameter_constraint rule that receives no parameters cannot evaluate constraints and will not protect you.

Authorization result fields

FieldTypeDescription
allowedbooleanWhether the action is permitted.
outcome"allowed" | "denied" | "escalated"The authorization outcome.
matchedPolicyIdstring | nullThe ID of the policy that produced the decision. null if the result is a default deny.
reasonstringA human-readable explanation of the decision.
evaluatedAtstringISO 8601 timestamp of when the evaluation occurred.

How evaluation works

Veto evaluates policies using the following logic:
  1. Sort by priority — enabled policies are sorted by priority descending. The highest priority policy is evaluated first.
  2. First match wins — evaluation stops as soon as a policy produces a definitive decision.
  3. Within a policy — each rule is evaluated. If any rule denies the request, the policy returns denied. If all relevant rules pass, the policy returns allowed.
  4. Default deny — if no policy produces a decision (no relevant rules matched any policy), Veto denies the request.
The default-deny reason is always: "No policy explicitly allows this action (default deny)".
A policy only applies to a tool call if it has at least one rule relevant to that tool. Policies with no matching rules are skipped, and evaluation continues to the next policy.

Fail-closed behavior

If the Veto API is unreachable — due to a network error or a timeout — the SDK denies the request by default. Your agent does not gain access because Veto was unavailable.
import { VetoClient, VetoError } from "@useveto/node";

const veto = new VetoClient({ apiKey: process.env.VETO_API_KEY! });

try {
  const result = await veto.authorize("agent-uuid", "file.write", { path: "/tmp/output.txt" });
  if (!result.allowed) {
    throw new Error(`Blocked: ${result.reason}`);
  }
  // safe to proceed
} catch (error) {
  if (error instanceof VetoError) {
    // Network errors, timeouts — treat as denied
    throw new Error("Authorization unavailable, action blocked");
  }
  throw error;
}
Do not configure fail-open behavior (onError: "allow") in production. If Veto cannot be reached, your policies cannot be enforced.

Audit log

Every authorization decision — allowed or denied — is recorded in the audit log with the agent ID, tool name, parameters, outcome, matched policy, reason, and latency in milliseconds. You can query the audit log at any time:
const entries = await veto.queryAuditLog({ agentId: "agent-uuid", result: "denied" });
See the audit logs guide for filtering options and examples.