Skip to main content
A connection declares one mint_url. There is no second field, so if both your product and the Patchwork runtime need tokens from you, that single endpoint has to serve both. They are genuinely different callers with different proofs and — this is the part that catches people — different response shapes.

Branch on the signature

The one reliable discriminator is whether the request carries a Patchwork-Signature header. A browser never has one; Patchwork always does.
Do not branch on a path, a query parameter, or a body field. Patchwork controls what it sends and it sends the signature.

Relay: Patchwork asking

Patchwork needs a token for a subject it is already acting for. It proves it is Patchwork with the presenter signature, and names the subject in the body:
Verify the signature (Signing and verification), then mint for that subject:
The relay response must be a bare { token, expires_in }. Patchwork reads token at the top level. If you wrap it in your API’s usual envelope — { "status": "success", "data": { "token": … } } — minting fails with mint response missing token and the run dies partway through.session_token is accepted as an alias for token.

Trust the subject, do not re-authorize it

The subject in the body is one Patchwork was already given — asserted by your own backend in relay, or verified from a token you signed in direct. You are not being asked whether this user exists; you are being asked to issue them a token. What you must do is mint for exactly that subject and no other. Never widen it, and never fall back to a default subject when the string is unfamiliar.

Direct: your browser asking

Your own frontend, minting for the signed-in user. There is no signature — authenticate it the way you authenticate any other endpoint in your product.
This branch may return whatever shape your frontend expects — Patchwork never reads it. Only the relay branch has a contract.
Patchwork’s own integration does exactly this. Its direct branch composes the subject as user_id:workspace_id, the same composite pattern we recommend, derived from the session rather than from the request.

What expires_in actually controls

Patchwork caches each minted token per (mint_url, subject) and reuses it, so a burst of tool calls mints once. So expires_in is not decorative. If you return an hour, Patchwork holds that token for an hour, and revoking early has no effect on calls already in flight. Keep it short.

Rotating your request secret

Verify the presenter signature against your current and previous secret, not just the current one:
Without this, rotating breaks every mint in flight at the moment you cut over. The signature timestamp is also checked against a 300-second window, so reject anything outside it.

The Playground needs the relay branch

This is the consequence people hit first, and it hits during testing rather than in production. Playground runs are trusted-internal — there is no browser and no session token on the request — so egress can only take the relay path. A connection using minted auth is testable in the Playground only if its mint URL handles the relay branch correctly. The subject Patchwork sends is the persona’s subject verbatim, so if your tools resolve a subject, the persona must name one your backend can find — see The Playground. Build only the direct branch and you get a working product with a Playground that fails inside a run:
Build the relay branch first. It is the one both paths depend on.

Checklist

required
A connection declares one mint_url. Handle both callers there.
required
Present means relay. Absent means your own frontend.
required
{ token, expires_in } at the top level. No envelope.
required
Current and previous, so rotation does not break minting.
required
Never widen it, never substitute a default.
recommended
It sets Patchwork’s cache lifetime, not just the token’s.