Browse documentation

Connect

Secrets and credentials

Let an agent request a credential without placing it in model context.

Flary can pause a thread and ask for a credential through a protected form. The model never receives the credential value. The value also stays out of prompts, events, and generated code.

export const operator = app.agent({
  name: "operator",
  model: "openai/gpt-5",
  tools,
  requestSecrets: true, // This is the default.
});

When a connector needs a key, the model uses the built-in request_secret tool. It supplies only safe information:

{
  connectionId: "github",
  secretName: "api-token",
  label: "GitHub personal access token",
  scope: "organization",
}

The request does not accept a value field. The product UI renders a password input and sends the value through the protected secret route:

const pending = await thread.userInput();
const request = pending.find((item) => item.request.metadata?.flarySecretRequest);

await thread.fulfillSecret(request.request.id, {
  value: valueFromPasswordInput,
});

Do not use thread.sendInput() for a secret request. Flary rejects that path. fulfillSecret() sends the value directly to the host’s encrypted secret store. The durable thread receives only this safe result:

{
  status: "stored",
  connectionId: "github",
  name: "api-token",
  scope: "organization",
  version: 1,
}

Trusted connector access

The application supplies a FlarySecretHostService to its host router. Store values with authenticated encryption, a tenant-specific additional-data value, and a managed key-encryption key. Return only ConnectionSecretMetadata.

The Cloudflare package includes this implementation:

import { CloudflareEncryptedSecretStore } from "flary/cloudflare";
import { createFlaryHostRouter } from "flary/host";

const secrets = new CloudflareEncryptedSecretStore({
  database: env.DB,
  encryptionKey: env.FLARY_SECRET_VAULT_KEY,
});

const router = createFlaryHostRouter({
  authorize,
  service: threadService,
  secrets,
});

FLARY_SECRET_VAULT_KEY is an unpadded base64url value that decodes to 32 bytes. Store it as a Worker secret. Do not put it in source code or D1.

Tools declare the secret references that they can use. Trusted host code can open a secret only inside a callback:

return context.useSecret("github/api-token", async (token) => {
  return callGitHub({ token, input });
});

The callback runs in trusted host code. The secret is not available to Code Mode, Dynamic Worker source, tool search, tool results, prompts, transcripts, events, logs, or public errors.

Scope

Use the smallest useful scope:

  • run: one finite run.
  • agent: one agent definition.
  • workspace: one file workspace.
  • project: one project.
  • organization: shared connector access for one tenant.

An encrypted value is required because API providers need the original token for authentication. A one-way hash cannot be used as an API key. Flary gives the model an opaque reference and decrypts the value only inside the trusted connector callback.

Set requestSecrets: false when an agent must never request credentials.