Skip to main content

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 thisExpect
No Authorization header401
Wrong --audience403
Tampered path/route after signingrequest_binding_mismatch
Replay the same signed requestjti_replay
Route not in the bundlebundle_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.