Token Vault

The Bulwark Token Vault stores third-party OAuth tokens — GitHub, Slack, Stripe, Google, and others — on behalf of users, so agents can use them securely through the credential proxy.

Why a Token Vault?

When a user connects a third-party app via OAuth, you receive an access token. Without a vault:

  • Tokens are stored in your database unencrypted (or weakly encrypted)
  • Agents need direct token access — tokens enter the LLM context
  • Token rotation requires updating many places
  • No centralized audit trail of token usage

With Bulwark's Token Vault:

  • Tokens are encrypted at rest with AES-256-GCM
  • Agents never see tokens — they access them via the proxy
  • Rotation is centralized
  • Every access is logged to the audit trail

Storing a Token

Typically done in your OAuth callback handler:

// After OAuth callback, store the token
app.get("/auth/github/callback", async (req, res) => {
  const { code } = req.query;
  const { accessToken, refreshToken, expiresAt } = await exchangeGitHubCode(code);

  await bulwark.vault.storeToken({
    provider: "github",
    userId: req.user.id,
    accessToken,
    refreshToken,
    expiresAt,
    scopes: ["repo", "read:user"],
  });

  res.redirect("/dashboard");
});

Token Lifecycle

OAuth Callback
  ↓ storeToken()
Encrypted in Vault
  ↓
Agent Session Created
  ↓ proxy() call
Bulwark decrypts token
  ↓
Injected into API request
  ↓
Response returned to agent
  ↓
Audit event written

Automatic Token Refresh

When a stored token expires, Bulwark automatically refreshes it using the stored refresh token before injecting it into a proxy request:

// You don't need to handle this — Bulwark does it automatically
const response = await session.proxy({
  credentialId: "cred_github",
  method: "GET",
  url: "https://api.github.com/user",
  // If the stored token is expired, Bulwark refreshes it first
});

Configure refresh behavior:

await bulwark.vault.storeToken({
  provider: "github",
  userId,
  accessToken,
  refreshToken,
  refreshUrl: "https://github.com/login/oauth/access_token",
  refreshClientId: process.env.GITHUB_CLIENT_ID,
  refreshClientSecret: process.env.GITHUB_CLIENT_SECRET,
});

Per-Agent Access Control

By default, a token is accessible only to the user who owns it. To grant an agent access:

await bulwark.fga.write({
  writes: [
    {
      user: `agent:${agentId}`,
      relation: "can_use",
      object: `vault-token:${tokenId}`,
    },
  ],
});

Revocation

// Revoke a single token
await bulwark.vault.revokeToken(tokenId);

// Revoke all tokens for a provider
await bulwark.vault.revokeTokensByProvider(userId, "github");

// Revoke all tokens for a user (e.g., account deletion)
await bulwark.vault.revokeAllTokens(userId);

Revocation immediately prevents any agent from using the token via the proxy.