TINFOIL_API_KEY on your backend. If you send it to a browser, anyone who obtains it can use your API quota. Prompts and completions should still be encrypted end-to-end to the attested enclave, not just to your backend.
A backend proxy lets you authenticate users, add your API key, track usage, and enforce rate limits without decrypting their prompts or completions. The Encrypted HTTP Body Protocol (EHBP) encrypts request and response bodies at the application layer using HPKE, independently of TLS. The proxy can read and modify HTTP headers but cannot decrypt the bodies. Every Tinfoil SDK automatically verifies that the HPKE key comes from an attested secure enclave.
Client Setup
The credential passed to the client is a token for your proxy, not your backend’s
TINFOIL_API_KEY. Your proxy should authenticate the token, remove it, and add TINFOIL_API_KEY before forwarding the request.baseURL differs from the enclave URL), it includes the enclave URL in the X-Tinfoil-Enclave-Url header. Your proxy should use this header to determine where to forward requests, ensuring the encrypted payload reaches the same enclave that the client verified.
- JavaScript
- Python
- Go
- Swift
- Rust
baseURL or base_url must point at your proxy, not a Tinfoil enclave. Include /v1/ for JavaScript, Python, and Go. Swift and Rust append API paths themselves.
Proxy Server Setup
Your proxy’s job is to preserve the EHBP protocol headers that coordinate encryption between client and enclave, add your authentication credentials, and forward the encrypted payload. No special cryptographic libraries are needed; the proxy never participates in encryption or decryption. While we provide an example implementation in Go below, the proxy pattern works with any language that can handle HTTP requests. The proxy example provides a complete reference implementation with a Go proxy and a TypeScript client.Required Endpoints
Your proxy needs to implement these routes:
The example below forwards every
/v1/ path so chat completions, responses, embeddings, audio, and other supported APIs use the same encrypted route.
Required Headers to Preserve
The EHBP protocol uses specific headers to coordinate encryption keys between the client and enclave. Your proxy must forward these headers unchanged in both directions. For requests, you need to preserveEhbp-Encapsulated-Key (the HPKE encapsulated key, hex-encoded, 64 characters).
For responses, you need to preserve Ehbp-Response-Nonce (the 32-byte nonce used in response key derivation, hex-encoded, 64 characters).
Understanding the body framing format isn’t necessary for proxy implementation, but it helps explain why these headers are critical: they contain the cryptographic material needed for key derivation and decryption.
CORS Configuration
If your proxy will be called from browser-based applications, you’ll need to configure CORS headers to allow the browser to send and read the encryption headers. The key requirement is exposing the EHBP headers in both directions:Implementation Example
Usage Metrics for Billing
Since EHBP encrypts request and response bodies, your proxy cannot read token counts from the JSON. Tinfoil provides usage metrics via HTTP headers so you can track usage and bill your users. To enable this, add theX-Tinfoil-Request-Usage-Metrics: true header when forwarding requests to the enclave. Tinfoil returns token counts in the X-Tinfoil-Usage-Metrics response header for non-streaming requests, or as an HTTP trailer after the body completes for streaming requests. The value is a comma-separated list of key=value pairs:
Parse the value as a map rather than by position, since optional fields may be added between existing ones.
For example:
Enforcing the Model
Because the body is encrypted, your proxy cannot see which model a request targets. If you want to allow-list models, apply per-model quotas, or bill by model, have clients send the model name in the optionalX-Tinfoil-Model header as well:
X-Tinfoil-Model unchanged when forwarding requests to the enclave; the check runs there, not in the proxy. Tinfoil compares the header to the model field in the decrypted body. If they differ, the request is rejected with a 400 error before any inference runs, so a client cannot claim one model in the header while requesting another in the body. When the header is absent, no check is performed.
The check applies to the OpenAI-compatible JSON endpoints (/v1/chat/completions, /v1/responses, /v1/embeddings, and similar). The header must match the body exactly, including case.
Custom Headers
In addition to the required EHBP headers, you can send custom HTTP headers for application metadata shared between the client and proxy. EHBP encrypts bodies, not headers, so the proxy can use that metadata to authenticate users, track requests, apply rate limits, or pass feature flags. The proxy can keep these custom headers out of requests forwarded to the enclave.Request Headers
The JavaScript SDK’s lower-levelSecureClient lets you send arbitrary headers and inspect the raw response:
Access-Control-Allow-Headers configuration so browsers can send them.
Response Headers
Your proxy can add custom headers to responses that the client can read. This is useful for communicating rate limit information, cost tracking, or request IDs for debugging:Access-Control-Expose-Headers configuration for browsers to access them.
Session Recovery
Streaming responses can take a while, and if the user closes the tab mid-stream the response is normally lost. Because your proxy already relays the encrypted stream, it can also buffer a copy. The proxy never decrypts anything; it stores the ciphertext under a session ID and serves it back later. The client keeps the key material needed to decrypt that buffer. The client sends a session ID with the request, then exports a recovery token from the active encryption context and saves it alongside the session ID:X-Session-Id, it writes the encrypted upstream response to a buffer as it forwards it. If the client disconnects, the proxy keeps the enclave connection open and continues buffering until the stream completes.
On the next page load, the client checks for a saved token, fetches the buffered ciphertext from the proxy, and decrypts it with the stored token:
Security Considerations
While EHBP encrypts the request and response bodies, the HTTP headers remain visible throughout the proxy chain. This design is intentional (it’s what allows proxies to route and manage requests), but it has important security implications.- Use HTTPS in production. While request and response bodies are encrypted at the application layer, HTTP headers (including custom headers like user IDs) are only protected by transport-layer encryption.
- Allowlist enclave destinations. Treat
X-Tinfoil-Enclave-Urlas untrusted input and only forward to approved HTTPS Tinfoil enclave origins. This prevents clients from using your proxy to reach arbitrary hosts. - Validate and sanitize custom headers from clients. Treat them as untrusted input: check formats, guard against injection attacks, and authenticate before trusting client-provided values.
- Always preserve and forward the EHBP headers (
Ehbp-Encapsulated-Keyfor requests,Ehbp-Response-Noncefor responses). Dropping or modifying them will cause decryption to fail.
How It Works
The data flow shows how encryption is maintained throughout the request lifecycle:This diagram shows the proxied attestation flow used by JavaScript, Python, Go, and Swift. Rust performs attestation directly against the enclave before routing encrypted inference requests through your proxy.
Next Steps
For a complete working example, check out the encrypted-request-proxy-example. It includes a Go proxy implementation with streaming support, a TypeScript browser client demonstrating theSecureClient, and custom header handling examples.
Proxy Example
Go proxy server with TypeScript browser client
Session Recovery Example
Resume encrypted streams after the client disconnects
Encrypted HTTP Body Protocol
Deep dive into the EHBP specification

