EERRAA // IDENTITY & VAULT

It acts as the right person, with their own secrets.

// a signed per-user identity the browser cannot forge, plus an encrypted vault that hands tools each user’s credentials without ever showing the model the raw value.

TWO MODES

01OPEN MODE

The agent trusts the identity you pass as-is. Good for personalization: it greets people by name and reads their role and data. Simple to start.

02SIGNED MODE

You sign the identity server-side with HMAC-SHA256 over canonical JSON plus a fresh timestamp, valid for 300 seconds. Now it is tamper-proof, and no browser can impersonate a user.

WHAT SIGNING UNLOCKS

PRIVATE UPLOADS

Only a signed user can add and retrieve their own knowledge documents.

THE VAULT

Reading or writing per-user credentials requires a signed identity.

PER-USER MCP OAUTH

Connecting an MCP server as an individual user is gated behind a signature.

MY TASKS PANEL

Scheduled tasks are tied to a signed user, so no one sees another’s queue.

SIGN IT SERVER-SIDE

A few lines on your backend.

The signing secret lives in Settings, Identity. Keep it on the server, never in a VITE_ or NEXT_PUBLIC_ variable. Sign the identity, pass it to the widget, done.

import { createHmac } from "crypto";

function stableStringify(v) {
  if (Array.isArray(v)) return "[" + v.map(stableStringify).join(",") + "]";
  if (v && typeof v === "object") {
    return "{" + Object.keys(v).sort()
      .map(k => JSON.stringify(k) + ":" + stableStringify(v[k]))
      .join(",") + "}";
  }
  return JSON.stringify(v);
}

function signUserContext(identity, secret) {
  const ctx = Object.assign({}, identity, { _ts: Math.floor(Date.now() / 1000) });
  ctx._sig = createHmac("sha256", secret).update(stableStringify(ctx)).digest("hex");
  return ctx; // identity + _ts + _sig, valid for 5 minutes
}

THE CREDENTIAL VAULT

ENCRYPTED AT REST

Every secret is Fernet-encrypted in the database. Caps of 50 credentials per user and 8 KB per value.

INJECTED, NOT EXPOSED

Reference a secret in tool auth as {{user.creds.name}}. It is substituted server-side. The raw value never reaches the model or the browser.

LIVE JWT PASSTHROUGH

Use {{user.auth_token}} to forward the user’s own token to your API, so the tool acts with exactly their permissions.

PROVISIONED SERVER-TO-SERVER

Your backend sets secrets with a signed PUT /v1/credentials. Names up to 64 chars, values up to 8 KB.

GO DEEPER// identify users →// per-user credentials →

Make it act as each user.

// signed identity and the vault are on Pro, free during beta.