Yak Docs

Security

Yak is designed with security as a priority. The widget runs in an isolated iframe, all communication is origin-validated, and your tool calls execute in your own server context with your existing authentication.

Key Security Features

  • Origin isolation — The widget iframe is sandboxed from your application's DOM
  • Origin validation — All messages are validated against expected origins; unexpected origins are rejected
  • Tool allowlisting — Only explicitly allowed tools can be executed
  • Server-side execution — Tool calls run on your server with your auth and access controls
  • Identity verification — Persist conversations per end-user with HMAC-signed user identities
  • Redirect protection — Built-in protection against open redirect attacks

Tool Security

Restricting Exposed Procedures

When using the tRPC adapter, control which procedures are available:

import { createTRPCToolAdapter } from "@yak-io/trpc";

const toolAdapter = createTRPCToolAdapter({
  router: appRouter,
  createContext,
  allowedProcedures: [
    "orders.list",
    "orders.getById",
    "products.search",
  ],
});

Always restrict procedures to the minimal set needed by the assistant. Avoid exposing destructive operations without safeguards.

Authentication

Tool calls receive the original Request object, so your existing auth works automatically:

const toolAdapter = createTRPCToolAdapter({
  router: appRouter,
  createContext: async ({ req }) => {
    const session = await getSession(req);
    if (!session) throw new Error("Unauthorized");
    return { user: session.user };
  },
  allowedProcedures: ["..."],
});

Input Validation

Tool inputs are validated against the JSON Schema derived from your Zod schemas. Always validate on the server side as well:

export const ordersRouter = router({
  list: protectedProcedure
    .input(z.object({
      limit: z.number().min(1).max(100).default(10),
      status: z.enum(["pending", "shipped", "delivered"]).optional(),
    }))
    .query(async ({ ctx, input }) => {
      return db.orders.findMany({
        where: { userId: ctx.userId, status: input.status },
        take: input.limit,
      });
    }),
});

User Identity Verification

When you want to persist conversations against a specific end-user (so they can resume past chats from the widget), the widget needs a tamper-proof way to know who's chatting. Yak uses the same HMAC pattern as Intercom and similar tools:

  1. Your application gets an apiSecret (revealable from your dashboard).
  2. Your backend signs the user id: hash = HMAC-SHA256(apiSecret, userId).
  3. The browser passes { id, hash } into <YakProvider user={...}>.
  4. Every Yak endpoint that touches user data re-verifies the hash with a constant-time comparison.
// Backend
import crypto from "node:crypto";

const userHash = crypto
  .createHmac("sha256", process.env.YAK_API_SECRET!)
  .update(currentUser.id)
  .digest("hex");
// Browser
<YakProvider
  appId={appId}
  user={{ id: currentUser.id, hash: userHash }}
/>

Never expose YAK_API_SECRET to the browser. Compute the hash on your server and send only the resulting hex string to the client.

Only the user id is HMAC-protected. A holder of the secret can produce a valid identity for any id, so keep the secret on the server.

If you suspect the secret has leaked, rotate it from the dashboard. Rotation invalidates every previously signed hash, so plan it alongside a deploy of your server code.

See End-user identity for the full guide and language-specific signing snippets.

Session Revocation

Each visitor's widget holds a short-lived, HMAC-signed session token that ties them to their conversation history. From your dashboard you can sign out all sessions for an app in one click — this immediately invalidates every outstanding session token, including any that may have leaked. On its next action, each widget transparently re-mints a fresh session; no visitor sees an error.

This resets session tokens — it does not lock users out. An anonymous visitor loses their conversation history and starts over. A signed-in end-user whose page still passes their signed identity simply re-binds the fresh session to the same account on their next request. To keep a specific person out for good, also stop signing their identity from your backend (i.e. your own logout).

Use it when you want to cut off outstanding sessions — a suspected token leak, or forcing everyone onto a fresh session — without disrupting your integration. It is distinct from rotating your apiSecret:

  • Sign out all sessions — one click, no redeploy. Only invalidates session tokens; your identity signing is untouched and the SDK auto-recovers.
  • Rotate apiSecret — invalidates every signed identity hash, so you must redeploy your backend with the new secret. Use it when the secret itself may have leaked.

Enforcement is applied on each visitor's next request (or page load), so it is effectively immediate for anyone actively using the widget.

Redirect Protection

The SDK validates all redirect paths:

  • Allowed: Relative paths (/dashboard, /settings), hash paths (#section), query paths (?tab=profile)
  • Blocked: External domain URLs, protocol-relative URLs (//evil.com)

To customize redirect behavior:

<YakProvider
  appId="your-app"
  onRedirect={(path) => {
    if (isAllowedPath(path)) {
      router.push(path);
    }
  }}
/>

Content Security Policy

If your application uses CSP headers, allow the widget iframe:

frame-src https://chat.yak.io;

Production Checklist

Before deploying to production, verify:

  • Tool allowlist — Only necessary procedures are exposed
  • Authentication — Tool requests require valid auth
  • Rate limiting — Consider rate limiting your tool endpoint
  • HTTPS — All endpoints use HTTPS
  • CSP headers — Allow frame-src chat.yak.io if using CSP
  • Logging — Tool invocations are logged for audit
  • Allowed origins — Restrict which domains can embed the widget (configure in your dashboard)
  • User identity — If you persist conversations per end-user, the apiSecret is server-only and the hash is computed on every page load (never cached client-side)

Reporting Security Issues

If you discover a security vulnerability, please report it responsibly:

  1. Do not create a public GitHub issue
  2. Email security@yak.io with details
  3. Include steps to reproduce if possible

On this page