This example shows how to proxy inference requests through your own servers while preserving end-to-end encryption using the Encrypted HTTP Body Protocol (EHBP).
EHBP encrypts HTTP message bodies using HPKE while keeping headers in plaintext. This lets your proxy inspect headers and route requests without being able to read the actual content.
├── server/
│ └── main.go # Go proxy server
└── clients/
├── typescript/ # Browser example
└── swift/ # macOS/iOS example
# Terminal 1: Start the proxy
export TINFOIL_API_KEY=tk_...
cd server && go run main.go
# Terminal 2: Start the TypeScript client
cd clients/typescript && npm install && npx viteOpen http://localhost:5173 and send a message.
- Go 1.21+
- Node.js 18+ (for TypeScript example)
- Swift 5.9+ (for Swift example)
- A Tinfoil API key
- Serves
/attestation— Proxies attestation bundles from Tinfoil so clients can verify enclaves - Forwards
/v1/chat/completionsand/v1/responses— Routes encrypted requests to the enclave specified in theX-Tinfoil-Enclave-Urlheader - Adds authentication — Injects your
TINFOIL_API_KEYas the Bearer token - Preserves encryption headers — Copies
Ehbp-Encapsulated-Key(request) andEhbp-Response-Nonce(response)
The proxy sees routing metadata but cannot decrypt the request or response bodies.
| Path | Method | Description |
|---|---|---|
/attestation |
GET | Proxy to https://atc.tinfoil.sh/attestation |
/v1/chat/completions |
POST | Forward to the URL in X-Tinfoil-Enclave-Url header |
/v1/responses |
POST | Forward to the URL in X-Tinfoil-Enclave-Url header |
| Direction | Header | Purpose |
|---|---|---|
| Request | X-Tinfoil-Enclave-Url |
The enclave URL the client verified — use as upstream |
| Request | Ehbp-Encapsulated-Key |
HPKE key for the enclave to decrypt the request |
| Response | Ehbp-Response-Nonce |
Nonce for the client to decrypt the response |
Access-Control-Allow-Headers: Ehbp-Encapsulated-Key, X-Tinfoil-Enclave-Url
Access-Control-Expose-Headers: Ehbp-Response-Nonce
Since EHBP encrypts request/response bodies, your proxy cannot see token counts in the JSON. Tinfoil provides usage metrics via HTTP headers so you can bill your users.
-
Request usage — Add this header when forwarding to Tinfoil:
X-Tinfoil-Request-Usage-Metrics: true -
Read the response — Tinfoil returns usage in the
X-Tinfoil-Usage-Metricsheader:X-Tinfoil-Usage-Metrics: prompt=67,completion=42,total=109 -
Streaming responses — For streaming (
text/event-stream), usage arrives as an HTTP trailer after the body completes. Read it fromresp.Trailerafter consuming the response body.
// When building the upstream request:
req.Header.Set("X-Tinfoil-Request-Usage-Metrics", "true")
// After receiving the response:
// Non-streaming: read from response header
if usage := resp.Header.Get("X-Tinfoil-Usage-Metrics"); usage != "" {
log.Printf("Usage: %s", usage) // "prompt=67,completion=42,total=109"
}
// Streaming: read from trailer after body is consumed
io.Copy(w, resp.Body)
if usage := resp.Trailer.Get("X-Tinfoil-Usage-Metrics"); usage != "" {
log.Printf("Usage: %s", usage)
}prompt=<prompt_tokens>,completion=<completion_tokens>,total=<total_tokens>
Parse with a simple split on , and =.
Client Proxy Tinfoil Enclave
│ │ │
│ GET /attestation │ │
│────────────────────────>│ GET /attestation │
│ │─────────────────────────────>│
│ │<─────────────────────────────│
│<────────────────────────│ attestation bundle │
│ │ │
│ (verify attestation) │ │
│ │ │
│ POST /v1/chat/completions │
│ X-Tinfoil-Enclave-Url: https://... │
│ Ehbp-Encapsulated-Key: <key> │
│ Body: <encrypted> │ │
│────────────────────────>│ │
│ │ POST /v1/chat/completions │
│ │ Authorization: Bearer <key> │
│ │ Ehbp-Encapsulated-Key: <key> │
│ │ X-Tinfoil-Request-Usage-Metrics: true
│ │ Body: <encrypted> │
│ │─────────────────────────────>│
│ │<─────────────────────────────│
│ │ Ehbp-Response-Nonce: <nonce> │
│ │ X-Tinfoil-Usage-Metrics: ... │
│ │ Body: <encrypted> │
│<────────────────────────│ │
│ Ehbp-Response-Nonce │ │
│ Body: <encrypted> │ │
│ │ │
│ (decrypt response) │ │
The proxy adds authentication and reads usage metrics, but cannot decrypt the bodies.