Tailrace
Guides

Block secrets in a Fastify app

Register the OpenAI-compatible Fastify plugin so chat requests and SSE responses respect Tailrace policy before they reach the model.

Use @tailrace/fastify to enforce data policy on OpenAI-compatible chat routes - in-process, with no proxy.

Prerequisites

Step 1: Install

pnpm add @tailrace/core @tailrace/fastify fastify

Step 2: Register the plugin

import { createTailrace } from "@tailrace/core";
import { tailraceFastify } from "@tailrace/fastify";
import Fastify from "fastify";

const app = Fastify();
const tailrace = createTailrace();

await app.register(
  tailraceFastify(tailrace, {
    agent: (req) => String(req.headers["x-agent-id"] ?? "default"),
    workflowId: (req) => String(req.headers["x-workflow-id"] ?? "default"),
  }),
);

// Your upstream proxy / chat handler routes...
await app.listen({ port: 3000 });

The plugin uses preHandler for the request check and onSend / stream wrapping for JSON and SSE responses. Ensure chat routes receive a parsed JSON body (Fastify's default JSON parser is enough).

How it works

LocationTailrace boundaryDirection
Chat request messages{ kind: "model", provider } (model field as-is)Outbound to upstream
JSON chat completionsame model boundaryInbound
SSE text/event-streamsame; carry-buffer across chunksInbound

When policy resolves to block, the plugin returns 422 with { error: { type: "policy_violation", entity, rule } } - never the raw value. That maps from PolicyViolationError.

For SSE, Tailrace cancels the upstream stream, emits one error data: event, and closes (abort-only in v0.1).

Only mode: "openai-compatible" is supported. Shared helpers live in @tailrace/http.

Common variations

Scope agent and workflow ID

Pass agent and workflowId as functions of FastifyRequest (or a static string for workflowId). Defaults are "default" when omitted.

By default, workflowId scopes tokens per request. For multi-turn agents that need tokens to resolve consistently across turns, see Tokenization and the vault.

NestJS + Fastify

If you use Nest's Fastify adapter, register @tailrace/fastify on the underlying Fastify instance rather than @tailrace/nestjs Express-shaped middleware. See Block secrets in a NestJS app.

Verify with a synthetic key

Send a chat completion body whose messages include sk_test_…FAKE. Expect 422. An example.com email should tokenize under the default policy.

See also

On this page