Broker a credential
Take the secret out of the agent entirely — including the material-key mistake that fails two layers from its cause.
The highest-value change you can make. An agent that holds an API key has that key in its prompt context, its logs, and whatever the model says next. Move it into the broker and prompt injection stops being credential theft.
#Register the credential
bashcurl -X POST https://veefore.example.com/v1/credentials \
-H "Authorization: Bearer $VEEFORE_API_KEY" \
-H 'content-type: application/json' \
-d '{
"key": "payments-api-key",
"name": "Payments service API key",
"type": "API_KEY",
"provider": "local",
"material": {
"api_key": "sk_live_…",
"header": "x-api-key"
}
}'
The response is metadata. No endpoint ever returns the material.
#Get material right
This is the mistake that costs an afternoon
Each credential type reads specific keys from material and discards the
rest. Put the secret under a name the broker does not read and the failure
appears two layers from its cause: Veefore seals and stores it, permits the
action, brokers nothing usable, and your downstream returns 401. Nothing in
the Veefore logs looks wrong, because from Veefore's point of view nothing was.
Veefore now refuses this at registration and at rotation with
INVALID_CREDENTIAL_REFERENCE rather than letting you find out in production.
| Type | Reads |
|---|---|
API_KEY |
api_key / apiKey / key / value, plus optional header, prefix |
BEARER_TOKEN |
token / access_token / value |
BASIC_AUTH |
username and password |
DATABASE_DSN |
dsn / url / connection_string |
OAUTH_CLIENT |
client_id and client_secret |
MTLS_CERTIFICATE |
certificate and private_key |
SIGNING_KEY |
private_key and algorithm |
BASIC_AUTH, MTLS_CERTIFICATE and SIGNING_KEY are exempt from the
single-secret check because their material is legitimately multi-field.
header and prefix control how an API_KEY is presented downstream:
json{ "api_key": "sk_live_…", "header": "x-api-key" }
{ "api_key": "sk_live_…", "header": "authorization", "prefix": "Bearer " }
#Attach it to a tool
bashcurl -X POST https://veefore.example.com/v1/tools \
-H "Authorization: Bearer $VEEFORE_API_KEY" \
-H 'content-type: application/json' \
-d '{
"workspace_id": "wsp_01JAV…",
"key": "refund_customer",
"name": "Refund a customer order",
"kind": "HTTP",
"required_capability": "refund.create",
"endpoint_url": "https://payments.internal.example.com/refunds",
"destination_allowlist": ["payments.internal.example.com"],
"credential_id": "cred_01JAV…"
}'
That is the whole integration. The agent never references the credential, never receives it, and does not need to know it exists.
#What happens at request time
Stage 10 of the pipeline — after authentication, identity, lifecycle, capability, delegation, policy, risk and approval have all passed:
- The broker unseals the material.
- It issues a lease: a short-lived credential scoped to this action.
- The tool runtime injects it into the outbound request.
- The lease is recorded by reference and expires.
Default lease lifetime is CREDENTIAL_DEFAULT_TTL_SECONDS, 600 seconds. Lease
statuses: ISSUED, USED, EXPIRED, REVOKED.
Why stage 10 and not earlier
Brokering is the first irreversible step. Everything before it can refuse with no trace outside Veefore.
Putting the broker last is what makes BLOCK mean blocked. Brokering earlier —
say, for latency — would mean a blocked action had already caused a credential
to be issued, and "we blocked it" and "the secret did not go out" would become
two different claims with only one of them true.
#Migrating an agent that already holds a key
Register the existing key as a credential
Same value, under the right material key for its type.
Attach it to the tool and authorize the agent
The agent can now reach the downstream through Veefore.
Switch the agent's calls to `act()`
Where it previously called your API directly with the key, it now calls
agent.act({ tool: 'refund_customer', … }).
Remove the key from the agent's environment
This is the step that actually achieves something. Until you do it, the agent still holds a usable credential and nothing has improved.
Rotate
The old value was in an agent's environment, possibly in its logs, possibly in a model provider's request history. Treat it as exposed.
bashcurl -X POST https://veefore.example.com/v1/credentials/cred_01ABC/rotate \
-H "Authorization: Bearer $VEEFORE_API_KEY" \
-H 'content-type: application/json' \
-d '{ "material": { "api_key": "sk_live_NEW…", "header": "x-api-key" } }'
#Rotation and revocation
Rotation invalidates every outstanding lease, so an in-flight action holding
an old lease fails rather than continuing with a credential you decided to
retire. Status moves through ROTATING while it happens.
bashcurl -X POST https://veefore.example.com/v1/credentials/cred_01ABC/revoke \
-H "Authorization: Bearer $VEEFORE_API_KEY" \
-H 'content-type: application/json' \
-d '{ "reason": "Key published in a support ticket" }'
Revocation is immediate. Every tool depending on the credential starts failing
at stage 10 with INVALID_CREDENTIAL_REFERENCE.
Both credential:rotate and credential:revoke require step-up
authentication, and credential:revoke is high impact.
#Diagnosing a downstream 401
Veefore allowed the action and your downstream rejected what it received. In order of likelihood:
- Wrong material key for the type.
api_keyversustokenversuskey. Now caught at registration, but an older credential may predate the check — rotate it and the check runs. - Wrong
header. Your downstream wantsx-api-key, you configuredauthorization, or vice versa. - Missing
prefix.authorizationusually needsBearerincluding the trailing space. - The key itself is wrong or revoked downstream.
veefore logs --limit 20 shows the stage results. A CREDENTIAL stage of
PASS with an EXECUTION stage carrying http_401 means Veefore brokered
something and your downstream did not accept it — which narrows it to the first
three.
#Providers
CREDENTIAL_BROKER_PROVIDER selects the backend. local seals material in
PostgreSQL with VEEFORE_DATA_ENCRYPTION_KEY, which is right for development
and for deployments where the Veefore database is already your trust boundary.
For production, point it at your existing secret manager so material lives where the rest of your secrets live and inherits that system's rotation, auditing and access control. Broker behaviour is identical either way.
Rotating the data encryption key requires re-sealing
VEEFORE_DATA_ENCRYPTION_KEY seals stored material under the local provider.
Changing it without re-sealing makes every credential unreadable at once, and
the symptom is every tool failing simultaneously. Plan it as a migration.