Connect an OAuth-protected agent
Register a protected Agent Card, configure a client-credentials binding, verify discovery, and manage rotation.
Taskbay can call OAuth-protected agents using the OAuth 2.0 client-credentials grant. Each agent has one server-side service credential shared by all authorized people. The console's OIDC login token is never forwarded to an agent.
The token endpoint is explicitly configured, uses HTTPS and must accept client_secret_post. Taskbay requests a bearer access token for each connection. There is no discovery of an agent's OAuth metadata, refresh-token flow, consent redirect, per-user token store, token exchange, configurable audience/resource parameter or automatic completion of in-task AUTH_REQUIRED authorization.
1. Prepare the agent and OAuth client
Get the Agent Card URL, every advertised HTTP interface origin, the OAuth issuer, the exact token endpoint, a client ID and client secret, and any required scope from the agent operator. The agent must offer JSON-RPC or HTTP+JSON; gRPC is unsupported.
In this example:
| Purpose | Example |
|---|---|
| Agent Card | https://catalog.example.com/team/card.json |
| A2A interface | https://agents.example.com/a2a |
| OAuth issuer | https://identity.example.com |
| Token endpoint | https://identity.example.com/oauth/token |
Origins include scheme, hostname and optional port, without a path. URLs must not embed credentials, queries or fragments.
2. Configure outbound policy and the vault
Generate a fresh 32-byte random vault key using openssl rand -hex 32. Store it as 64 hex characters in the key ring, using your own key ID:
A2A_ALLOWED_AGENT_ORIGINS=https://catalog.example.com,https://agents.example.com,https://identity.example.com
A2A_VAULT_KEYS='{"key-1":"REPLACE_WITH_64_HEX_CHARACTERS"}'
A2A_VAULT_ACTIVE_KEY=key-1Set the same key ring and outbound policy on web and every worker, then restart them. The allowlist must include both the card and interface origins and the token endpoint origin. It also needs the notification webhook origin when enabled. A configured allowlist is enforced in development as well as production.
Production requires HTTPS and blocks private/loopback addresses by default. For an intentionally internal agent, set A2A_ALLOW_PRIVATE_NETWORKS=true while retaining a narrow allowlist. Metadata, link-local and reserved ranges remain blocked. DNS is checked on the actual connection, redirects are rejected and TLS validation stays enabled.
3. Register the protected card URL
As an administrator, open Agents → Add agent. If Fetch Agent Card fails because the card itself requires a credential, choose Register URL to save the URL without fetching it. Preview sends no credentials.
Obtain the local agent UUID from the catalog or the id field of GET /api/agents. This is the ID used by the credential CLI, not the agent's remote name or card URL.
4. Store an OAuth binding through stdin
Create binding.json in an operator-controlled location with restrictive permissions. Replace every REPLACE_... value before running the command:
{
"origins": [
"https://catalog.example.com",
"https://agents.example.com"
],
"credential": {
"type": "oauthClient",
"issuer": "https://identity.example.com",
"tokenEndpoint": "https://identity.example.com/oauth/token",
"clientId": "REPLACE_WITH_CLIENT_ID",
"clientSecret": "REPLACE_WITH_CLIENT_SECRET",
"scope": "REPLACE_WITH_AGENT_SCOPE"
}
}Omit scope if the authorization server does not require one. The binding's origins constrain where the resulting bearer token can be sent; list both the protected card and all interface origins that need it. The token endpoint is separately authorized by the global allowlist and the OAuth request's own destination constraint.
chmod 600 binding.json
npm run security:credentials -- --organization acme --agent REPLACE_WITH_AGENT_UUID --action store < binding.json
rm binding.jsonUse your actual organization slug (local for local development, or A2A_AUTH_ORGANIZATION_SLUG for OIDC). With PGlite, stop web and add --offline-pglite. Migrations must already be applied. Do not pass secrets in CLI arguments or commit the file. The credential CLI loads .env files, prints no secret values and reports a generic error on failure.
The vault encrypts the binding as JWE with dir and A256GCM, bound to the organization and agent. The fetched access token is held in process memory, not persisted. The token endpoint must return a nonempty bearer token of at least eight characters.
5. Verify discovery and permission separately
After Agent credential binding updated., check Settings → Agent credentials for an enabled oauthClient binding. Settings shows status, never the secret. Run discovery on the registered agent and inspect its interfaces, skills, security schemes and trust status. Then start a chat as an administrator.
For operators and viewers, add grants in Settings → Teams and access. A working credential proves Taskbay can authenticate to the agent; it does not grant a person permission to use it. The card's security schemes are displayed and validated for shape, but do not automatically select or negotiate a credential type.
Rotate and revoke
Store a new binding to rotate the client secret; this replaces the prior binding and enables it. Revoke with:
npm run security:credentials -- --organization acme --agent REPLACE_WITH_AGENT_UUID --action revokeLater calls fail closed with Agent credentials are disabled. rather than becoming anonymous. An in-flight call can finish.
For vault-key rotation, add the new key while retaining old keys, switch A2A_VAULT_ACTIVE_KEY, restart all processes, and run --action reencrypt for every enabled binding. Remove old keys only when no bindings need them. A revoked binding requires a replacement instead. Back up the vault keys separately from the database; losing a needed key makes its bindings unreadable.
Other credential types
All types use the same origins envelope and the same CLI lifecycle:
| Type | Credential fields | Behavior |
|---|---|---|
apiKey | name, value | Custom header. Host, cookie, connection, content/transfer and proxy-authorization headers are restricted. |
bearer | token | Authorization: Bearer .... Rotation is manual. |
oauthClient | issuer, tokenEndpoint, clientId, clientSecret, optional scope | Client credentials with client_secret_post; bearer response only. |
mtls | PEM cert, key, optional ca | Mutual TLS; server certificate validation remains on. |
Bindings allow 1–20 exact HTTPS origins. Secret fields are 8–100000 characters, client IDs at most 255, scope at most 1000; the CLI accepts at most 256000 bytes on stdin. Extra fields are rejected. HTTP Basic, query-string keys, cookie credentials and simultaneous multiple credential schemes are not supported by the binding schema.
Troubleshoot the failing boundary
| Error | Check |
|---|---|
Agent OAuth credentials unavailable. | Token endpoint allowlist, HTTPS/TLS, endpoint/client/secret/scope, support for client_secret_post, bearer response. The UI deliberately hides endpoint error detail. |
Agent credential destination is not permitted. | Binding origins include the card and selected interface origins. |
Agent target is not in the configured origin allowlist. | Global policy includes card, interface and token endpoint origins. |
Credential vault unavailable. | Valid key ring and active ID, matching keys in all processes, retained encryption keys. |
Agent credentials are required. | A card declares security requirements but no credential binding is available. |
Agent Card trust policy rejected this connection. | Inspect signature trust separately from OAuth: pin the correct unexpired public key for the card origin. |
To require signed cards, configure A2A_TRUSTED_CARD_KEYS and A2A_REQUIRE_SIGNED_CARDS=true. OAuth protects calls; a trusted card signature establishes the card's configured signing identity. Neither replaces human grants.
Sources and related guides
- Connect an agent, Agent credentials, Service identity, Compatibility.
- Implementation: credential schema, connection/token flow, encrypted vault.
Created and maintained by Shashi Kanth G S at allsrc.dev. Visit shashikanth.me.