Credentials Overview
Provider family, dispatch adapter, blocklist; BYOK credential binding per auth mode; per-mode cost attribution.
Rensei's credential system is a pluggable provider family that resolves secrets at agent session spawn time, delivers them as environment variables into the agent's execution context, and keeps them fresh through live rotation subscriptions.
BYOK auth-mode binding
A model profile's credentials map ({ authMode → credentialId }) links a credential row to the byok auth mode:
{ "byok": "cred_abc123" }The credential is only used when byok is the resolved auth mode. If the profile's auth_modes set includes both byok and metered, and the resolver picks metered (because the effective allowed modes exclude byok at this scope), the credentials.byok entry is ignored entirely. Other auth modes (metered, shared, host-session, local) resolve credentials platform-side and never require a profile-level credential entry.
Per-mode cost attribution: Every dispatch emits a cost event stamped with the resolved scalar authMode. This means the cost ledger can break down spend by auth mode:
| Auth mode | Cost event pool ID |
|---|---|
byok | The capacity pool ID assigned to the org's BYOK key |
metered | metered_pool_{providerId} (e.g. metered_pool_claude) |
shared | shared_pool_{providerId} (e.g. shared_pool_gemini) |
host-session, local | The local pool ID |
Dispatches that fail at the access gate (denied mode, unsatisfiable intersection) emit no cost event.
Architecture
The credential system has two layers:
Registry level (CredentialProvider): One instance per backend. Org-scoped, stateless. Knows how to resolve(req) a credential kind for an org and optionally subscribeRotations() to receive upstream rotation events.
Session level (CredentialDispatchAdapter): Constructed once per agent session at spawn time. Calls snapshot() to build the complete env-var map, then wires onRotate() so the daemon can push credential deltas to the running agent without restarting.
Default provider: rensei-encrypted
All organizations use rensei-encrypted by default. It stores credential payloads AES-GCM encrypted in the credentials table. The encryption key is a deployment-level secret configured by the platform operator.
# Set credentials via the Settings UI: Settings → Security → Credentials
# Or via the API:
curl -X POST https://rensei.ai/api/org/credentials \
-H "Authorization: Bearer rsk_live_..." \
-H "Content-Type: application/json" \
-d '{
"kind": "anthropic-api-key",
"value": "sk-ant-..."
}'External providers
Four external providers are available for organizations that store secrets outside the Rensei database. Each is opt-in per-org and configured through Settings → Security → Credential Backend.
| Provider | ID | Auth modes |
|---|---|---|
| HashiCorp Vault | hashicorp-vault | token, AppRole, Kubernetes |
| 1Password | 1password-cli | service-account, cli, Connect |
| AWS Secrets Manager | aws-secrets-manager | static IAM, role-assumption, IRSA |
| GCP Secret Manager | gcp-secret-manager | service-account JSON, ADC, Workload Identity |
External providers do not auto-register. They are activated per-org when you configure the provider backend in Settings. Each provider reads its own configuration from a dedicated credentials row (with the appropriate providerType).
See the provider-specific pages for setup details:
Credential kinds
A credential kind is a stable string identifier for a category of secret (e.g. anthropic-api-key, linear-oauth, github-app-token). Kinds are not enumerated at the provider level - the kind namespace is open. The platform uses kinds to look up the right credential row for a given integration at session spawn time.
Snapshot at session spawn
When an agent session is dispatched, the platform calls snapshot(scope) to build the complete env-var map:
interface CredentialDispatchScope {
orgId: string
projectId?: string // narrows to project-specific credentials
envName?: string // narrows to environment-specific credentials
sessionId: string // keys the rotation subscription
}Resolution priority (for each credential kind):
- Project + environment-specific row matching
(projectId, envName) - Project-default row matching
(projectId)with no env constraint - Org-default row matching
(orgId)with no project or env constraint
The returned Record<string, string> is merged into the agent's environment immediately before process exec, after the blocklist filter.
Live credential rotation
If an upstream secret rotates during a session (e.g., an OAuth token refresh), the dispatch adapter delivers the updated value to the running agent without restarting:
GET /api/daemon/credentials/rotate-stream?sessionId=...This is a Server-Sent Events stream. Each event carries a delta - the partial env-var map with only the changed variables. The daemon forwards the delta to the agent over the credential socket.
AGENT_ENV_BLOCKLIST
A hardcoded blocklist filters daemon-internal tokens from the agent's environment snapshot. Daemon-internal variables are never exported into a child process. This prevents a compromised agent from obtaining the daemon's own authentication material.
Multi-field credentials
Some integrations require multiple related fields rather than a single API key. Jira, for example, uses { site, email, apiToken }. These are stored as multi-field credentials.
Multi-field credentials are not included in the snapshot() env-var map today. Consumers that need Jira-shape credentials call resolveProviderCredentialRaw(orgId, providerType) directly. The dispatch adapter flattens multi-field credentials into prefixed env vars (JIRA_SITE, JIRA_EMAIL, JIRA_API_TOKEN) when it encounters them - but only for explicitly supported kinds.
CredentialValue contract
Every provider's resolve() returns a CredentialValue:
interface CredentialValue {
value: string // primary scalar (may be empty for multi-field creds)
source: string // provider id that produced this value
resolvedAt: Date // wall-clock resolution time
refreshAt?: Date // optional next-refresh hint (Vault lease, OAuth expiry)
multiField?: Record<string, string> // Jira-style multi-field payloads
}Providers set refreshAt to guide the dispatch adapter's re-resolve schedule. When refreshAt is absent, the credential is treated as static for the session lifetime.
Registry chaining
External providers (Vault, 1Password, AWS, GCP) may themselves need to store a sub-credential (e.g., the service-account token for 1Password, the secret-access-key for AWS). These are resolved by chaining through credentialProviderRegistry.getDefault() - meaning the bootstrap secret is always stored in rensei-encrypted, never inline in the external provider's config row.
API endpoints
| Endpoint | Description |
|---|---|
GET /api/org/credentials | List credential kinds for the org |
POST /api/org/credentials | Create or update a credential |
DELETE /api/org/credentials/:kind | Delete a credential kind |
POST /api/daemon/credentials/snapshot | Internal - builds the session env-var map |
GET /api/daemon/credentials/rotate-stream | Internal - SSE rotation stream |
Related pages
- Auth Modes - how the resolver selects a mode and when the credential is used
- Model Profiles -
credentialsmap ({ authMode → credentialId }) on profiles - HashiCorp Vault
- 1Password
- AWS Secrets Manager
- GCP Secret Manager
- Workflow Environments - env-aware credential scoping
- Org Hierarchy - org/project/environment model and access constraints