Protect your first API
You have an existing HTTP service and you want only verified, proof-bound requests to reach it — without changing the service itself. This tutorial puts the TrustPlane adapter in front of your API to do exactly that. It takes about 10 minutes, all local.
What you’ll build
Section titled “What you’ll build”flowchart LR C["Your client"] -->|"passport + proof"| A["trustplane-adapter"] A -->|"verified only"| U["Your existing API"] A -. "401 / 403 / deny" .-> C
Step 1 — Prepare local binaries
Section titled “Step 1 — Prepare local binaries”Use the verified CLI archive from Install and artifacts, or build from a TrustPlane Auth source checkout:
make buildStep 2 — See the adapter behavior with the demo
Section titled “Step 2 — See the adapter behavior with the demo”Before wiring your own service, watch the adapter prove the three core outcomes:
make demo-adapterYou will see: a valid passport reaches the upstream; a missing passport returns 401; a wrong
audience returns 403. This is the exact behavior you’ll get in front of your own API.
Step 3 — Build trust material and a route policy
Section titled “Step 3 — Build trust material and a route policy”Create an authoring config describing your route and the client source you’ll allow, then build the bundle:
trustplane bundle build --config bundle.config.json --out trustplane.bundle.jsonThe route entry decides what’s allowed (issuer, trust domain, subject, key binding) and how fresh
the policy must be (freshness_class). See
Bundle policy for the full shape. Generate the client’s key
with trustplane gen-key and put its public key in the trust material.
Step 4 — Run the adapter in front of your service
Section titled “Step 4 — Run the adapter in front of your service”Point the adapter’s --upstream at your existing API and mount the bundle:
./bin/trustplane-adapter \ --upstream http://127.0.0.1:8080 \ --policy-bundle ./trustplane.bundle.json \ --route-policy-mode request \ --proof-mode transcript-v1--route-policy-mode request lets one adapter protect many routes by matching the request
method/path against the bundle’s method + path_template.
Step 5 — Make a verified call
Section titled “Step 5 — Make a verified call”Sign a request (no broker needed) and send it:
trustplane sign \ --private-key "$CLIENT_KEY" \ --method GET --path /orders \ --audience acme.demo.orders \ --route-id acme.demo.orders.read \ --curlRun the emitted curl. It succeeds. Now tamper with the path (call /orders-tampered with the
same proof) and you’ll get request_binding_mismatch. Send the same valid request twice and the
second returns jti_replay.
Step 6 — Confirm the failure modes
Section titled “Step 6 — Confirm the failure modes”| Try this | Expect |
|---|---|
No Authorization header |
401 |
Wrong --audience |
403 |
| Tampered path/route after signing | request_binding_mismatch |
| Replay the same signed request | jti_replay |
| Route not in the bundle | bundle_route_missing |
What you achieved
Section titled “What you achieved”- Your API is now reachable only through verified, short-lived, request-bound calls.
- You added zero verification code to the upstream.
- Adding another client later is a bundle change, not a redeploy — see Brownfield APIs for that flow.
- The same adapter can accept local software, EC2-style, SPIFFE/SPIRE, or automation callers when each source is explicitly allowed. See the use cases overview.
Next steps
Section titled “Next steps”When you’re ready to run this in front of a live API, continue to the deployment overview.