Get Started

Secrets

Securely inject API keys, tokens, and credentials into agent sandboxes. Secrets are encrypted at rest, scoped to sessions, and never exposed in logs.

How secrets work

Secrets are per-session key-value pairs that get injected as environment variables into the agent sandbox. They're encrypted with AES-256-GCM using per-platform derived keys (HKDF), and are never logged or returned in API responses.

set-secrets.ts
import { Theazo } from 'theazo'

const theazo = new Theazo({ apiKey: 'th_live_...' })
const session = await theazo.sessions.forUser('user_123')

// Set secrets for this session
await session.secrets.set({
  OPENAI_API_KEY: 'sk-...',
  STRIPE_SECRET:  'sk_live_...',
  DATABASE_URL:   'postgres://user:pass@host:5432/db',
})

// Agents in this session can access these as env vars
const agent = await session.agents.create({
  compute: 'python',
  secrets: ['OPENAI_API_KEY', 'STRIPE_SECRET', 'DATABASE_URL'],
})

// Inside the sandbox:
// process.env.OPENAI_API_KEY → 'sk-...'
// process.env.STRIPE_SECRET  → 'sk_live_...'
Secrets are only injected into agent sandboxes that explicitly request them via the secrets array in agent create options. An agent cannot access secrets it didn't declare.

Dual-scope secrets

Secrets can be scoped at two levels: org-wide and session-scoped. This lets you set shared credentials once for the entire organization while still allowing per-session overrides.

Org-wide secrets

Org-wide secrets are available to all sessions in your organization. Set them directly on the Theazo client without any session context. Ideal for shared API keys, service credentials, and infrastructure tokens.

org-secrets.ts
import { Theazo } from 'theazo'

const theazo = new Theazo({ apiKey: 'th_live_...' })

// Set org-wide secrets (no session context)
await theazo.secrets.set({
  STRIPE_KEY:    'sk_live_...',
  SENDGRID_KEY:  'SG...',
  GITHUB_TOKEN:  'ghp_...',
})

// These are now available to every session in the org

Session-scoped secrets

Session-scoped secrets are only available within that specific session. Use them for per-user credentials, short-lived tokens, or anything that shouldn't leak across sessions.

session-secrets.ts
const session = await theazo.sessions.forUser('user_456')

// Set session-scoped secrets (only this session can access them)
await session.secrets.set({
  USER_OAUTH_TOKEN: 'ya29...',
  STRIPE_KEY:       'sk_test_user_specific_...',
})

Resolution order

When an agent requests a secret, Theazo resolves it using a session-first strategy:

  • 1. Session-scoped — If the secret exists on the session, use it
  • 2. Org-wide — Otherwise, fall back to the org-wide value
  • 3. Not found — If neither scope has the key, the agent gets no value for that env var
resolution.ts
// Org-wide: STRIPE_KEY = 'sk_live_org_...'
await theazo.secrets.set({ STRIPE_KEY: 'sk_live_org_...' })

// Session-scoped: STRIPE_KEY = 'sk_test_user_...'
await session.secrets.set({ STRIPE_KEY: 'sk_test_user_...' })

const agent = await session.agents.create({
  compute: 'python',
  secrets: ['STRIPE_KEY'],
})

// Inside the sandbox:
// process.env.STRIPE_KEY → 'sk_test_user_...'
// Session-scoped wins because it overrides org-wide
Use org-wide secrets for shared infrastructure keys like STRIPE_KEY, SENDGRID_KEY, or GITHUB_TOKEN. Use session-scoped secrets for per-user OAuth tokens or credentials that should be isolated between users.

Listing secrets

List secret names for a session. Values are never returned — only metadata.

list-secrets.ts
const secrets = await session.secrets.list()

// secrets = [
//   { name: 'OPENAI_API_KEY',  createdAt: '2025-05-01T10:00:00Z' },
//   { name: 'STRIPE_SECRET',   createdAt: '2025-05-01T10:00:00Z' },
//   { name: 'DATABASE_URL',    createdAt: '2025-05-01T10:00:00Z' },
// ]

Updating secrets

Call secrets.set() again to update existing secrets or add new ones. Running agents are not affected — they use the value from when their sandbox was created.

update-secrets.ts
// Update an existing secret
await session.secrets.set({
  OPENAI_API_KEY: 'sk-new-key-...',
})

// The old value is overwritten. New agents get the new value.
// Running agents still have the old value in their sandbox.

Deleting secrets

delete-secrets.ts
await session.secrets.delete('OPENAI_API_KEY')
// Secret is permanently removed
// Agents that declared it will fail if they try to access it

Security model

  • Encrypted at rest — AES-256-GCM with per-platform keys derived via HKDF
  • Never logged — Secret values are excluded from all logs, traces, and API responses
  • Session-scoped — Secrets are isolated to the session that created them
  • Explicit access — Agents must declare which secrets they need at creation time
  • Env injection — Secrets are set as environment variables in the sandbox, not passed as arguments
Never pass secrets as task input or agent instructions. Always use the secrets API so values are encrypted and not visible in logs.

API reference

session.secrets.set(kv)Promise<void>Set one or more secrets as key-value pairs. Overwrites existing keys.
session.secrets.list()Promise<SecretInfo[]>List secret names and creation timestamps. Values are never returned.
session.secrets.delete(name)Promise<void>Delete a secret by name.

REST endpoints

POST/v1/sessions/:sid/secretsSet secrets (body: key-value object)
GET/v1/sessions/:sid/secretsList secret names (values not returned)
DELETE/v1/sessions/:sid/secrets/:nameDelete a secret

SecretRef in workflows

Instead of hardcoding credentials in workflow step configs, use a secretRef to reference a stored secret by name. Theazo resolves the reference at runtime, decrypts the value, and injects it into the step — the plaintext never appears in your workflow definition or logs.

workflow-secret-ref.ts
import { Theazo } from 'theazo'

const theazo = new Theazo({ apiKey: 'th_live_...' })
const session = await theazo.sessions.forUser('user_123')

const workflow = await session.workflows.create({
  name: 'deploy-and-notify',
  steps: [
    {
      id: 'build',
      type: 'agent',
      task: 'Run the build pipeline',
      environment: {
        // SecretRef — resolved and decrypted at runtime
        GITHUB_TOKEN: { secretRef: 'GITHUB_TOKEN' },
        NPM_TOKEN:    { secretRef: 'NPM_TOKEN' },
      },
    },
    {
      id: 'notify',
      type: 'webhook',
      url: 'https://hooks.slack.com/services/...',
      headers: {
        Authorization: { secretRef: 'SLACK_BOT_TOKEN' },
      },
      inputMap: { text: '$.steps.build.output' },
    },
    {
      id: 'charge',
      type: 'agent',
      task: 'Create a Stripe charge for the deployment',
      environment: {
        STRIPE_KEY: { secretRef: 'api_key_prod' },
      },
    },
  ],
})

await session.workflows.run(workflow.id)

secretRef works anywhere a credential is needed: webhook step headers, agent environment variables, and tool configurations. The referenced secret follows the same dual-scope resolution — session-scoped first, then org-wide.

Using secretRef ensures your workflow definitions are safe to store, share, and version-control. The actual credentials are resolved only at execution time from the encrypted secret store.
Was this page helpful?
Ask anything...⌘I