Scripts credential broker
How scripts authenticate to external APIs without raw secrets in source, args, or logs.
The scripts credential broker lets swarm scripts authenticate outbound fetch
calls without receiving the raw secret in script source or arguments. A script
sends a [REDACTED:<configKey>] placeholder in a request header or query
parameter, and the runtime swaps that placeholder for the real config value only
when the destination host is allowlisted.
This broker is part of the scripts-runtime fetch layer. It is not a dynamic
MCP tool generator, and it does not expose a new SDK method to unwrap secrets.
Binding model
Bindings live in swarm_config under SCRIPT_CREDENTIAL_BINDINGS. The document
can be either an array of bindings or an object with a bindings array:
{
"bindings": [
{
"configKey": "GITHUB_TOKEN",
"allowedHosts": ["api.github.com"],
"headerTemplate": "Authorization: Bearer [REDACTED:GITHUB_TOKEN]",
"scope": "global",
"scopeId": null,
"active": true
}
]
}Each binding has:
configKey— the config key to resolve with the normal swarm config resolution path.allowedHosts— exact hostnames where this credential may be substituted.headerTemplate— optional header shape containing the[REDACTED:<configKey>]placeholder.queryTemplate— optional query shape likeapi_key=[REDACTED:VENDOR_API_KEY].scope/scopeId—global,agent, orreposcoping for where the binding applies.active— set tofalseto keep a binding in config but stop using it.
At least one of headerTemplate or queryTemplate is required.
Default GitHub binding
Fresh runtimes include a backward-compatible default binding:
{
"configKey": "GITHUB_TOKEN",
"allowedHosts": ["api.github.com"],
"headerTemplate": "Authorization: Bearer [REDACTED:GITHUB_TOKEN]",
"scope": "global",
"scopeId": null,
"active": true
}If GITHUB_TOKEN resolves from swarm config or the process environment, scripts
can call GitHub by sending the placeholder header:
await fetch("https://api.github.com/repos/desplega-ai/agent-swarm", {
headers: {
Authorization: "Bearer [REDACTED:GITHUB_TOKEN]",
},
});The script never sees the raw token. The fetch patch substitutes the header only
when the request hostname is api.github.com.
Query-string credentials
Some APIs require credentials in the query string. Configure a queryTemplate
for those APIs:
{
"configKey": "VENDOR_API_KEY",
"allowedHosts": ["api.vendor.example"],
"queryTemplate": "api_key=[REDACTED:VENDOR_API_KEY]",
"scope": "global",
"active": true
}Then the script sends the placeholder query value:
const url = new URL("https://api.vendor.example/v1/items");
url.searchParams.set("api_key", "[REDACTED:VENDOR_API_KEY]");
await fetch(url);The broker does not add missing query parameters. It only replaces placeholders that are already present on allowlisted hosts.
Operator workflow
Lead agents manage bindings through the static credential-bindings MCP tool.
The tool writes SCRIPT_CREDENTIAL_BINDINGS to swarm_config; the runtime reads
that config when a script starts.
If you want scripts to call a typed external API instead of hand-written
fetch() calls, pair the broker with the lead-only script-connections tool.
That registry stores an OpenAPI spec, allowed hosts, and the optional backing
credential binding, then generates a typed ctx.api.<slug> client for swarm
scripts.
Typical flow:
- Create or update the credential binding with
credential-bindings. - Register the OpenAPI-backed API connection with
script-connections. - Call the generated
ctx.api.<slug>helpers from the script instead of embedding raw URLs and auth logic in source.
Global-scope config mutations now live-reload the runtime, so updated bindings
and script connections take effect without a manual /api/config/reload.
For manual config management, keep the binding document non-secret. The secret
value belongs in the separate swarm config key named by configKey, such as
VENDOR_API_KEY, with isSecret enabled.
Security boundary
The placeholder flow is:
- The script subprocess receives resolved binding metadata and secret values
through the internal
egressSecretspayload. eval-harness.tsinstalls the credential-broker fetch patch before user code runs.- On each
fetch, the patch checks the request hostname. - If the hostname is in
allowedHosts, placeholders in configured headers or query parameters are replaced with the real secret value. - If the hostname is not allowlisted, the placeholder remains redacted.
This means a script can opt in to using a credential for an approved API without being able to redirect the same placeholder to another host and leak the secret.
Request-body and path substitution are intentionally not supported today. Add those only with a separate host-allowlisted substitution mode and tests that preserve the same placeholder discipline.
Scripts as external APIs
Expose a saved swarm script as a public, JSON-in/JSON-out HTTP endpoint — POST /api/x/script/<id> — with optional bearer auth, typed input validation, and per-endpoint usage tracking.
One-off Script Workflow Runs
Launch, inspect, and operate durable one-off TypeScript workflow runs without registering a reusable DAG.