Programmable authority for machine actors · the next evolution of OAuth

Authority you can prove.

Give your agents real authority, never give them a key. OAuth let you grant apps scoped access without handing over your password. Latch is the next leap: real spending power, real API access, real execution rights. All of it bounded, revocable, and proven on every request, without ever handing over a credential it can leak.

policy-trace·GET/access
live
·evaluating pipeline · latch lat_visitor_anon
·├─methodGET, POST·
·├─endpoint/access·
·├─rate_limit60 / min·
·└─identityallowlist·
··awaiting verdict…
Request beta access
identity.allowlist. First deny wins. Add your identity to satisfy the policy:

Agent filling this out? POST /access-requests (see /llms.txt)

requests

Already hold a workspace key?

Not less power.
Bounded power.

Latch isn't about restricting agents. It's about finally being able to use them, for the things you couldn't safely let them touch before.

Spend

Give an agent a real budget, enforced at the edge. The over-budget call returns 403 before it leaves your network.

Act

Real API access, real execution rights, scoped per relationship. One token, many upstreams, each with its own policy.

Audit

Every request is a receipt. Drill into the pipeline trace, replay it, prove what happened and why it was allowed.

Stay private

Every other gateway has to read your data in plaintext to govern it. Latch enforces policy on encrypted payloads inside attested hardware. Govern the call without anyone, including us, seeing it in the clear.

// 01The problem

You handed an agent your API key.
Now it can do anything that key can do.

The problem isn't just that keys leak. It's that possession is the wrong proxy for authority. An agent shouldn't be powerful because it holds a secret, only because policy proves it's allowed, for this action, right now.

And the API can't help you here: it executes on possession alone. It has no idea what this caller is allowed to spend, what it's already spent, or whether this call should happen. That context lives in a doc nobody reads and a billing page you check Monday, never at the call site, where it could actually stop anything.

// today

Same scenario, raw key.

# .env
OPENAI_API_KEY=sk_live_…m4n2

# assistant.ts: full authority,
# any model, any endpoint, any budget
await openai.chat.completions.create({
  model: "gpt-4o",
  max_tokens: 16000,
  messages: [...],
});
  • One key. The assistant can also hit /v1/fine-tunes, /v1/files, anything.
  • No cap on max_tokens. A loop = a five-figure bill.
  • Revoking means rotating the key, and a panic in #eng.
  • Audit is "check the upstream's billing page on Monday".
// with Latch

Same scenario, scoped token.

# .env
LATCH_TOKEN=lat_assistant_3f2a

# assistant.ts: same call, governed
await openai.chat.completions.create({
  model: "gpt-4o",
  max_tokens: 16000,         # → denied
  messages: [...],
}, { baseURL: process.env.LATCH_URL });
  • One Secret, many latches. This one only hits /v1/chat/completions.
  • max_tokens ≤ 4096 at the edge. The 16k call returns 403 before it ever leaves your network.
  • Revoke the latch, the credential keeps living. No rotation panic.
  • Every request is a receipt. Drill into the pipeline trace, replay it.
// 02How it works

Four primitives.
Everything else is composition.

Drop in today. Harden when you're ready.

Point your agent at a latch instead of the raw key. That's the whole integration, no rewrite. Your credential is already governed: scoped, rate-limited, audited, revocable. When your threat model demands it, wrap secrets and policy end-to-end with HPKE encryption in a few lines, so nothing, not even Latch, sees the payload in the clear.

01

Secret

The raw credential. Never leaves Latch. Bind it once.

Stored server-side, encrypted at rest. The Secret defines what the credential is and how to inject it into upstream calls.

POST /admin/secrets
{ "name": "OpenAI prod",
  "credential": "sk_live_…m4n2",
  "injection": "bearer" }
02

Latch

A scoped access token derived from a Secret.

Give your agent a latch, not the Secret. Each latch has its own upstream base URL and its own filter pipeline. Many latches can fan out from one Secret.

lat_jordan_eng_3f2a
└── upstream  https://api.openai.com
└── pipeline  6 filters
└── enabled   yes
03

Pipeline

An ordered list of filters. First deny wins.

Composable: add, remove, reorder filters without touching the Secret. Conditional filters skip themselves cleanly, so payload validation can run only on writes, for instance.

[ method, endpoint, rate_limit,
  payload, ip_allowlist, response ]
↓
allow → upstream / deny → 403
04

Mount

One token, many upstreams. Path prefix routes the call.

Mounts are the composition layer. /openai → OpenAI, /stripe → Stripe, /schedule → a calendar API, all under one token, with per-mount pipelines and per-mount SLAs.

lat_… ─┬─ /openai  → OpenAI
        ├─ /stripe  → Stripe
        ├─ /sched   → Schedule API
        └─ /self    → self-discovery

A toolkit of composable filters.

Mix declarative and procedural. Cedar policies sit alongside your own JS. When you need shape no built-in covers, drop in custom_code.

endpoint
allowlist / blocklist URL paths
method
restrict HTTP verbs
rate_limit
sliding window, keyed by latch or IP
payload
JSON path rules, 14 operators
body_size
max payload bytes
time_window
business hours, timezone-aware
ip_allowlist
CIDR ranges or exact IPs
header_req
require headers with optional regex
response
redact, block, or trim upstream
custom_code
your JS or Rust, with governed outcalls
cedar
declarative Cedar 4.x policies
endpoint
allowlist / blocklist URL paths
method
restrict HTTP verbs
rate_limit
sliding window, keyed by latch or IP
payload
JSON path rules, 14 operators
body_size
max payload bytes
time_window
business hours, timezone-aware
ip_allowlist
CIDR ranges or exact IPs
header_req
require headers with optional regex
response
redact, block, or trim upstream
custom_code
your JS or Rust, with governed outcalls
cedar
declarative Cedar 4.x policies
// 03Policies as code

When a checkbox
isn't enough.

For anything the built-in filters don't quite cover, write the policy in Rust. You get the full request context, governed outcalls to other latches, and a return type that's just Decision::allow() or Decision::deny(reason). Compiles to WASM, ships attested into REX, runs in single-digit milliseconds.

  • Strongly typed context. No string-fishing.ctx.body.u64("$.max_tokens") means a u64.
  • Governed outcalls. http_get() routes through Latch under another token. Caching, depth limits, audit lines: all enforced.
  • Same engine, JS or Rust. Prototype in custom_code JavaScript, promote to Rust + REX when the policy gets serious.
policy.rs
target · wasm32-wasip2↳ REX attested
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// policy.rs · compiled to WASM, shipped to REX
use latch::{Context, Decision, http_get};
 
#[latch::policy]
fn evaluate(&ctx: &Context) -> Decision {
// 1. method allowlist
if !matches!(ctx.method, "GET" | "POST") {
return Decision::deny("method not allowed");
}
 
// 2. spend cap on chat completions
if ctx.path == "/v1/chat/completions" {
let max = ctx.body.u64("$.max_tokens").unwrap_or(0);
if max > 4096 {
return Decision::deny(format!("max_tokens {} exceeds 4096", max));
}
}
 
// 3. governed outcall · check on-call rotation, cache 60s
let oncall = http_get("/oncall/who").cache_ttl(60).send()?;
if oncall["user"] != ctx.headers["x-user"] {
return Decision::deny("only on-call may use this latch");
}
 
Decision::allow()
}
compiled · 142 KB · 26 linesattestation 0x6f1a…d44eeval p99 · 3.8msdeploy:⌘⏎
// 04Derivation, not duplication

One credential.
A whole org's worth of agency.

This is what bounded power looks like in practice. One master key never moves. Everyone, and every agent, downstream gets exactly the authority policy allows: the VP gets full models and a high ceiling, the contractor gets a small budget that expires, the bot gets read-only with PII redacted. Each can do real work. None holds the master key. Revoke any node and its descendants follow.

  • Inherit pipeline, add filters, never subtract.
  • Live request rate visible per node.
  • Revoke any node, and descendants follow.
  • SLA terms attach to nodes too.
OPENAI_PROD_KEY
sk_…m4n2 · 1 master key
VP Eng · Maria
142/min
gpt-4o16k tokensall endpoints
Engineer · James
38/min
gpt-4o8k tokensno recording
Contractor · Priya
4/min
gpt-4o-mini1k9–6 ETexpires Jul 26
Engineering Bot
91/min
read-only1k/hr
Bot's helper agent
17/min
read-only200/hrPII redacted
// derivation chain · revoke any node, all descendants follow
// 05Trust primitives

Pick the security level
your threat model demands.

Trusted Executionpolicy runs inside the enclave
HPKE encryptionwrap secrets + WASM end-to-end
Distributed keygenthreshold keys split across parties, no single point of compromise
Hardware-bound IDmeasurement-derived identity
Remote attestationverify code before you trust it
WASM sandboxpolicies run in a sealed VM
Signed receiptsevery decision, cryptographically
Threshold signaturesk-of-n decision quorum
Append-only audittamper-evident request log
Bilateral SLAowner pipeline + consumer terms
// REX runs on attested hardware · compose only the primitives you need
in private beta · talk to us

One token per agent.
One policy per relationship.

The bearer key was built for humans. Your agents need the next thing: authority they're granted, not a secret they hold.

Latch is in private beta. Request access at the top of the page and we'll send back a workspace key + a short call to walk through your stack.