Security and trust
Security and trust
BehalfID is designed to verify agent actions before they happen, keep secrets out of public views, and make denied actions fail closed when integrated.
This page explains the enforcement model, what secrets are stored and how, the public passport design, and the current known limitations.
Enforcement model
BehalfID does not magically control an agent by itself. The app or provider must call BehalfID before acting. If the action is denied, the integration should fail closed and not execute the action.
Fail closed means the agent throws on denial and the code that would execute the action never runs. The opposite — fail open — would let the agent proceed if the check fails or is unavailable. BehalfID's recommended enforcement pattern is always fail closed.
const result = await behalf.verify({
agentId,
action: "purchase",
vendor: "coachella.com",
amount: 742
});
if (!result.allowed) {
throw new Error(`Blocked by BehalfID: ${result.reason}`);
}
// Only execute the action after this point.Enforcement only works when the integration calls BehalfID before acting and respects the response. See the live sandbox for a browser-based demonstration.
Manual mode limitations
Manual mode is for testing with existing agents — Ollie, ChatGPT, Claude, Zapier, Make, or others — without requiring the provider to integrate BehalfID.
A passport link shares active permission scopes in a structured format any AI can read. An agent memory block is a text snippet that can be pasted into a system prompt. Neither constitutes enforcement — they are advisory inputs.
Because BehalfID cannot intercept requests to third-party providers, manual mode relies entirely on the external model reading and respecting the listed permissions. A model that ignores instructions or hallucinates permission grants cannot be stopped by BehalfID in manual mode.
POST /api/verify before the tool runs and fail closed on denial.Secrets and token storage
BehalfID stores the following credentials:
- API keys (
bhf_sk_…) — stored as SHA-256 hashes. A key is shown to you exactly once at creation time. If lost, it cannot be recovered; rotate to get a new one. - Passport tokens (
bhf_pt_…) — stored as SHA-256 hashes. Anyone who obtains a passport token can read the active permission scopes for that agent. Treat passport tokens as secrets. - Webhook signing secrets — stored as SHA-256 hashes. Verify incoming webhook signatures with
verifyWebhookSignaturebefore processing. - Developer passwords — hashed with scrypt. Plaintext passwords are never stored.
BehalfID never transmits credentials in plaintext in API responses. Keys are shown once, then discarded.
Public passport safety
A public passport URL (behalfid.com/passport/[agentId]) is designed to be shareable. It shows only what an AI assistant needs to know about its current permission scope.
The passport page does not expose:
- API keys or key hashes
- Webhook secrets or signing keys
- Account owner email or personal data
- Internal agent IDs (beyond what is visible in the URL)
Audit logs
Every verification request produces an immutable audit log entry. Entries include:
- Request ID (stable, for cross-system correlation)
- Agent ID and action
- Decision (allowed / denied / approval-required)
- Risk level and denial reason
- Timestamp
Logs are scoped to your account and visible in the developer portal. Verification logs are retained for 90 days. You can delete individual log entries or all logs from the logs page.
Webhooks and signing
BehalfID signs every webhook payload with HMAC-SHA256. The signature is in the X-BehalfID-Signature header.
Always verify signatures before processing events. The SDK exports a verifyWebhookSignature(secret, rawBody, signature) helper. Webhook delivery records are retained for 30 days.
Revocation
| Action | Effect |
|---|---|
| Revoke a permission | The next verify call for that action returns denied immediately. |
| Disable an agent | All verify calls for that agent are denied while it is disabled. |
| Rotate an API key | The old key stops working at the next request. A new key is shown once. |
| Regenerate a passport link | The old passport token becomes invalid. Anyone with the old link can no longer read scopes or run previews. |
Known limitations
BehalfID has the following known limitations. Please read these carefully before using the platform for sensitive or production workloads.
- No provider-native integrations yet. Connected agents are represented manually inside BehalfID — BehalfID does not call Ollie, ChatGPT, Claude, or Zapier APIs on your behalf.
- Manual mode depends on user and agent cooperation. The external agent must read the passport and respect the listed constraints; BehalfID cannot enforce behavior inside third-party providers.
- Site Guard is a planned website-owner enforcement pattern, not a global crawler blocker. It only protects routes or workflows where the website installs middleware, a proxy, worker, or gateway that calls BehalfID and respects the decision.
- No enterprise SSO or team roles yet. The admin console uses one shared password. The developer portal has individual accounts but no organizations.
- No formal external security audit yet. BehalfID is suitable for constrained deployments and demos, not open public multi-tenant use without further hardening.
- Not a replacement for app-level authorization. BehalfID is a pre-action verification layer. Your app still needs its own auth, input validation, and access control.
- Rate limiting falls back to process memory without Upstash Redis. In serverless environments, in-memory counters are not shared across instances.