Credential Proxy

The Bulwark Credential Proxy allows agents to call external APIs without ever seeing the underlying credentials.

The Problem

When an AI agent needs to call GitHub, Slack, Stripe, or any other API, it needs a token. Naively, you'd inject the token into the agent's context or environment. But:

  • The token is now in the LLM's context window — it could be echoed, logged, or leaked in a prompt injection attack
  • The token has no scope restriction — a compromised agent has full access
  • There's no audit trail of which API calls were made
  • Rotating credentials requires updating every agent

How the Proxy Works

Agent
  ↓  POST /sessions/{id}/proxy
  ↓  { credentialId: "cred_github", method: "GET", url: "..." }
  ↓
Bulwark Proxy
  ↓  1. Validate agent's Biscuit token
  ↓  2. Check FGA policy (is this agent allowed to use this credential?)
  ↓  3. Retrieve credential from encrypted vault
  ↓  4. Inject Authorization header
  ↓  5. Forward request to target API
  ↓  6. Write audit event
  ↓
Target API (GitHub, Slack, etc.)
  ↓
Bulwark Proxy → Response → Agent

The agent never receives the credential value — only the API response.

Setup

1. Store the credential

await bulwark.vault.storeToken({
  provider: "github",
  userId: "usr_01j...",      // the user who owns this credential
  accessToken: "gho_...",
  scopes: ["repo", "read:user"],
});

2. Define access policy

await bulwark.fga.write({
  writes: [
    {
      user: "agent:agent_01j",
      relation: "can_use",
      object: "credential:cred_github",
    },
  ],
});

3. Proxy a request

const session = await bulwark.sessions.create({
  agentId: "agent_01j...",
  userId: "usr_01j...",
  requestedScopes: ["credential:github"],
});

const response = await bulwark.sessions.proxy(session.sessionId, {
  credentialId: "cred_github",
  method: "GET",
  url: "https://api.github.com/user/repos",
});

Security Properties

  • Credentials never leave the vault — only injected at request time
  • Each proxy call is logged — target URL, method, response code, timestamp
  • FGA-gated — agents can only use credentials they're explicitly authorized for
  • Scope-limited — the stored credential's OAuth scopes are respected
  • Session-scoped — proxy access expires with the session

Supported Providers

Out-of-the-box proxy templates for:

| Provider | Auth Method | |----------|-------------| | GitHub | OAuth token / PAT | | Slack | OAuth token | | Stripe | API key | | Linear | API key / OAuth | | Notion | OAuth token | | Google APIs | OAuth token | | Custom | Bearer / Basic / API Key header |