Tutorial: protect your first API
Goal: put the TrustPlane adapter in front of an existing HTTP service so that only verified, proof-bound requests reach it — without changing the service.
Time: ~10 minutes, all local.
What you'll build
Step 1 — Prepare local binaries
Use the verified private preview CLI archive from Install & artifacts, or build from a pre-release TrustPlane Auth source tree:
make build
Step 2 — See the adapter behavior with the demo
Before wiring your own service, watch the adapter prove the three core outcomes:
make demo-adapter
You 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 + 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.json
The 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
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
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 \
--curl
Run 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
| 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
- 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 — that's the next tutorial: Add a client, no redeploy.
When you're ready to run this in front of a live API, continue to Deployment overview.