Worker Credentials
Daemon credentials snapshot and rotate-stream SSE.
Workers resolve per-org credentials before starting an agent session and stay synchronized with credential rotations via a Server-Sent Events stream. Both endpoints require a Bearer rsk_* key (getCliOrSessionAuth) - cookie auth is not supported on the /api/daemon/* prefix.
These endpoints are distinct from the /api/org/* routes. The /api/daemon/* prefix specifically supports CLI bearer token auth. Do not call /api/org/* credential endpoints from daemon workers - they are cookie-only and will return 403.
Credential snapshot
Fetch the resolved environment map for an agent session. The platform merges org-level, project-level, and environment-level credentials into a flat Record<string, string> ready for injection into the agent's process environment.
POST /api/daemon/credentials/snapshot
Authorization: Bearer rsk_live_<daemon_key>
Content-Type: application/jsonRequest body
{
"orgId": "org_01abc...",
"projectId": "proj_01abc...",
"envName": "production",
"sessionId": "sess_01abc..."
}| Field | Type | Required | Description |
|---|---|---|---|
orgId | string | Yes | Organization ID |
projectId | string | Yes | Project ID for project-scoped credential lookup |
envName | string | No | Environment name for environment-aware resolution (e.g. production, staging). Defaults to production. |
sessionId | string | No | Session ID for audit linkage |
Success response
{
"env": {
"LINEAR_API_KEY": "lin_api_...",
"GITHUB_TOKEN": "ghs_...",
"ANTHROPIC_API_KEY": "sk-ant-...",
"CUSTOM_SECRET": "value"
},
"refreshUntil": "2026-06-02T13:00:00Z"
}| Field | Description |
|---|---|
env | Flat Record<string, string> of resolved credential environment variables |
refreshUntil | ISO 8601 timestamp indicating when to re-snapshot (credentials may rotate before this) |
Blocklist
The snapshot endpoint filters out daemon-internal tokens that must never reach child agent processes. Keys matching the blocklist are silently omitted from the env response, even if they are present in the resolved credentials:
- Daemon authentication tokens and other daemon-internal keys
- Internal platform tokens declared in the blocklist
The canonical blocklist is maintained in donmai/internal/credentials/blocklist.go (OSS). The platform implementation is kept in sync manually. If you notice a sensitive variable leaking into agent environments, report it as a security issue.
Credential rotate-stream (SSE)
Subscribe to a real-time stream of credential rotation events. The platform emits UPDATE events whenever an upstream credential rotates (e.g. an OAuth token refresh from ensureLinearTokenFresh).
GET /api/daemon/credentials/rotate-stream
Authorization: Bearer rsk_live_<daemon_key>This is a long-lived HTTP connection (Server-Sent Events). Set a sufficiently high timeout on your HTTP client.
Query parameters
| Parameter | Description |
|---|---|
sessionId | Required. The session ID to watch for credential updates. |
orgId | Optional. Org scope for the stream. Derived from the API key if omitted. |
Example
curl -N "https://app.rensei.ai/api/daemon/credentials/rotate-stream?sessionId=sess_01abc..." \
-H "Authorization: Bearer rsk_live_..."SSE event format
event: UPDATE
data: {"key":"LINEAR_API_KEY","value":"lin_api_new_...","rotatedAt":"2026-06-02T12:30:00Z"}
event: UPDATE
data: {"key":"GITHUB_TOKEN","value":"ghs_new_...","rotatedAt":"2026-06-02T12:31:00Z"}| Field | Description |
|---|---|
key | The environment variable name that was rotated |
value | The new credential value |
rotatedAt | ISO 8601 timestamp of the rotation |
The daemon should update the in-memory credential map when it receives an UPDATE event, so that the next agent subprocess (or a running subprocess that supports live credential injection) uses the fresh value.
Multi-field credentials
Some provider credentials have a structured shape that does not fit the flat Record<string, string> model. For example, Jira requires { site, email, apiToken }. These are not included in the snapshot and must be resolved separately via resolveProviderCredentialRaw by platform-internal code.
For self-hosted workers, this means Jira and similar multi-field providers are currently resolved by the platform before dispatching work - the resolved fields appear as individual JIRA_SITE, JIRA_EMAIL, JIRA_API_TOKEN variables in the snapshot if the provider is configured to export in that style.
Go example (rensei-tui style)
type SnapshotRequest struct {
OrgID string `json:"orgId"`
ProjectID string `json:"projectId"`
EnvName string `json:"envName,omitempty"`
SessionID string `json:"sessionId,omitempty"`
}
type SnapshotResponse struct {
Env map[string]string `json:"env"`
RefreshUntil time.Time `json:"refreshUntil"`
}
func FetchCredentialSnapshot(ctx context.Context, apiKey string, req SnapshotRequest) (*SnapshotResponse, error) {
body, _ := json.Marshal(req)
httpReq, _ := http.NewRequestWithContext(ctx, "POST",
"https://app.rensei.ai/api/daemon/credentials/snapshot",
bytes.NewReader(body))
httpReq.Header.Set("Authorization", "Bearer "+apiKey)
httpReq.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(httpReq)
if err != nil {
return nil, err
}
defer resp.Body.Close()
var result SnapshotResponse
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
return nil, err
}
return &result, nil
}Related pages
- Worker Registration - registering a daemon worker
- Session Lifecycle - session state transitions
- Credentials Overview - provider families, dispatch adapter, blocklist