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.