Credential Broker
The credential broker gives your agents the secrets they need without putting those secrets in the agents' configuration. AI agents need credentials to act on external services: API keys, OAuth tokens, database passwords, service account keys. Without governance, agents end up with long-lived secrets pasted into their configuration, with no audit trail and no way to revoke them.
The MITRITY credential broker holds the secret value in an encrypted vault, and gives agents only time-bound, agent-scoped, revocable access.
The three-tier model
This is the most important idea on this page. There are three objects, and each exists for a different reason:
- A credential is the secret value itself. It is encrypted at rest in the MITRITY vault and never visible in API responses. You create it once, and rotate it when needed.
- A grant authorizes one specific agent to request leases for one specific credential. Without a grant, an agent cannot ask for the secret, whatever other permissions it has. Grants are the "who is allowed to use this", so a grant is also where you stop an agent (see Stopping an agent from using a credential).
- A lease is the time-bound record of a checkout. When an agent needs the secret, its gateway or sidecar takes out a lease, the broker validates the grant, and the agent retrieves the secret value through the gateway. Leases expire automatically. Revoking a lease marks it as revoked in the lease history, and doesn't stop the agent.
┌────────────┐ ┌────────────┐ ┌────────────┐
│ Credential │──► │ Grant │──► │ Lease │
│ (the value)│ │ (who can) │ │ (a use) │
└────────────┘ └────────────┘ └────────────┘
1 per secret N agents per N leases per
credential grant
When you remove one of them:
- Delete a credential, and its grants and leases are deleted with it. No agent can check it out after that.
- Remove a grant, or disable it, and that agent can no longer check the credential out. Its leases stay in the lease history as they were.
Credential types
Four types are supported. The type is descriptive metadata. It doesn't change how the value is stored, but it shows up in the dashboard and the audit log, so you can filter and search by it.
| Type | Typical contents |
|---|---|
api_key | API keys and bearer tokens: OpenAI, Stripe, SendGrid, etc. |
oauth_token | OAuth 2.0 access tokens and refresh tokens |
db_password | Database connection passwords: PostgreSQL, MongoDB, Redis |
service_account | Cloud service account credentials: GCP service account JSON, AWS IAM access keys |
Storage
All credentials are stored in the MITRITY built-in vault. MITRITY does not integrate with external secret managers such as GCP Secret Manager, AWS Secrets Manager or HashiCorp Vault.
Defining a credential
Via the dashboard
- Open the customer portal and go to Controls → Credentials in the sidebar.
- Click Add credential.
- Fill in:
- Name: a unique identifier within your tenant, e.g.
openai-production-key. - Type: one of
api_key,oauth_token,db_password,service_account. - Value: the actual credential. It is never displayed again after you save.
- Max TTL (minutes): the longest single lease an agent can request against this credential.
- Max concurrent leases: how many leases can be active at once. Start at 1 if your agent makes sequential calls.
- Rotation reminder (days): optional metadata for your own rotation tracking.
- Name: a unique identifier within your tenant, e.g.
- Save.
Via the API
curl -X POST https://api.mitrity.com/api/v1/credentials \
-H "Authorization: Bearer mk_your-api-key" \
-H "Content-Type: application/json" \
-d '{
"name": "openai-production-key",
"credential_type": "api_key",
"store_type": "builtin",
"credential_value": "sk-proj-abc123...",
"max_ttl_minutes": 60,
"max_concurrent_leases": 3,
"rotation_days": 90
}'
Response:
{
"id": "8b6c4a2e-...",
"tenant_id": "9f1a3d-...",
"name": "openai-production-key",
"credential_type": "api_key",
"store_type": "builtin",
"store_reference": null,
"has_value": true,
"max_ttl_minutes": 60,
"max_concurrent_leases": 3,
"rotation_days": 90,
"created_at": "2026-03-01T10:00:00Z",
"updated_at": "2026-03-01T10:00:00Z"
}
The credential value is never returned in any API response after creation. Only has_value: true/false tells you whether a value is stored.
Request fields (create)
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Unique name within the tenant |
credential_type | enum | Yes | api_key, oauth_token, db_password, or service_account |
store_type | enum | No | Defaults to builtin, the only supported value. |
credential_value | string | Yes | The actual secret (encrypted at rest before storage) |
max_ttl_minutes | int | Yes | Maximum lease TTL allowed against this credential (1-1440) |
max_concurrent_leases | int | No | Defaults to 1. Max active leases at once (1-100) |
rotation_days | int | No | Rotation interval, stored as metadata for your own tracking. It sends no reminders (see Limitations) |
Granting access to an agent
A grant says "agent X is allowed to lease credential Y". Without a grant, the agent's lease request returns 403 Forbidden, even if the agent has every other permission.
curl -X POST https://api.mitrity.com/api/v1/credentials/{credential_id}/grants \
-H "Authorization: Bearer mk_your-api-key" \
-H "Content-Type: application/json" \
-d '{
"agent_id": "3a5e1c-...",
"allowed_operations": ["read"],
"enabled": true
}'
This call is idempotent. Granting again to an agent that already has a grant updates it in place (allowed_operations + enabled) instead of failing. The response is 201 Created on the first grant, and 200 OK on a later update.
Grant fields
| Field | Type | Required | Description |
|---|---|---|---|
agent_id | UUID | Yes | The agent authorized to lease this credential |
allowed_operations | array | No | Operations granted. Defaults to ["read"]. |
enabled | bool | No | Defaults to true. Set false to suspend without deleting. |
To list the grants on a credential:
curl https://api.mitrity.com/api/v1/credentials/{credential_id}/grants \
-H "Authorization: Bearer mk_your-api-key"
To revoke a single agent's grant and leave the others in place, pass agent_id:
curl -X DELETE "https://api.mitrity.com/api/v1/credentials/{credential_id}/grants?agent_id={agent_id}" \
-H "Authorization: Bearer mk_your-api-key"
To remove all grants on a credential, omit agent_id. Their leases stay in the lease history:
curl -X DELETE https://api.mitrity.com/api/v1/credentials/{credential_id}/grants \
-H "Authorization: Bearer mk_your-api-key"
Stopping an agent from using a credential
The grant decides whether an agent gets a credential, so the grant is where you stop it. Revoking its leases doesn't: a revoked lease is only marked in the lease history, and the agent's gateway or sidecar takes out a new lease at its next checkout.
To stop an agent from getting a credential, remove its grant: on the credential's Grants tab in the dashboard, or with the DELETE call above. To keep the grant for later, disable it instead:
curl -X POST https://api.mitrity.com/api/v1/credentials/{credential_id}/grants \
-H "Authorization: Bearer mk_your-api-key" \
-H "Content-Type: application/json" \
-d '{
"agent_id": "3a5e1c-...",
"allowed_operations": ["read"],
"enabled": false
}'
What happens next:
- The broker refuses the agent's next checkout of the credential at once, with
403 Forbidden. - When you remove the grant, a gateway or sidecar that holds the value in its cache drops it at its next heartbeat, within 30 seconds. A disabled grant leaves the agent's credential list unchanged, so the cached value runs out instead, within 60 seconds: the cache's default lifetime.
Removing or disabling the grant doesn't take back a value that was already handed out: a value returned to the agent, a credential file already written to disk, or a request already in flight. Such a value keeps working at its provider. If the agent may have seen the secret, rotate the credential and revoke the old value at its provider, as in the runbook.
To stop the agent's actions as well, use the Governance Lifecycle gate: while the gate is on Enforce, the edge refuses the actions of an agent the gate denies, and the broker refuses its checkouts.
Leases — how agents actually get the secret
A lease is the time-bound record of one checkout:
- When the agent needs the value, its Mitrity Gateway or MCP Sidecar takes out a lease and starts the clock. The broker releases the value only while the agent holds an enabled grant on the credential.
- The agent receives the credential value through the Mitrity Gateway or MCP Sidecar, at the moment it actually needs the value.
The lease creation endpoint never returns the secret. It returns the lease metadata only.
Creating a lease
curl -X POST https://api.mitrity.com/api/v1/credentials/{credential_id}/leases \
-H "Authorization: Bearer mk_your-api-key" \
-H "Content-Type: application/json" \
-d '{
"agent_id": "3a5e1c-...",
"ttl_minutes": 30
}'
Response:
{
"id": "5d2f7a-...",
"credential_id": "8b6c4a2e-...",
"agent_id": "3a5e1c-...",
"issued_at": "2026-03-01T10:05:00Z",
"expires_at": "2026-03-01T10:35:00Z",
"status": "active"
}
A lease created through this endpoint is a record. The agent's gateway or sidecar takes out its own lease each time it checks the value out, under the agent's grant. See Integration Modes for how the gateway resolves credentials at runtime.
Lease fields
| Field | Type | Required | Description |
|---|---|---|---|
agent_id | UUID | Yes | The agent the lease is being issued to |
ttl_minutes | int | Yes | Lease duration. Must be ≤ the credential's max_ttl_minutes. |
Lease lifecycle
| Status | Meaning |
|---|---|
active | The lease runs until expires_at. |
expired | The TTL has elapsed. The agent must request a new lease. |
revoked | The lease was marked revoked before its TTL ran out. The mark is a record, and doesn't stop the agent. |
Revoking a single lease
Revoking a lease marks it revoked in the lease history, with the reason you give. It doesn't cut the agent off: its next checkout takes out a new lease, and is allowed while the agent's grant is enabled. To stop an agent, see Stopping an agent from using a credential.
curl -X POST https://api.mitrity.com/api/v1/credentials/{credential_id}/leases/{lease_id}/revoke \
-H "Authorization: Bearer mk_your-api-key" \
-H "Content-Type: application/json" \
-d '{ "reason": "Credential rotation in progress" }'
Listing leases
curl "https://api.mitrity.com/api/v1/credentials/{credential_id}/leases" \
-H "Authorization: Bearer mk_your-api-key"
Updating a credential (rotation)
You can replace a credential's value and keep the same id, grants and lease history. Every checkout after the update receives the new value. A gateway or sidecar drops the old value from its cache at its next heartbeat, within 30 seconds. A copy of the old value that was already handed out keeps working at its provider until you revoke it there.
curl -X PUT https://api.mitrity.com/api/v1/credentials/{credential_id} \
-H "Authorization: Bearer mk_your-api-key" \
-H "Content-Type: application/json" \
-d '{ "credential_value": "sk-proj-new-key-xyz789..." }'
Updatable fields
| Field | Type | Description |
|---|---|---|
name | string | Rename the credential (doesn't affect grants) |
credential_value | string | Replace the secret value |
max_ttl_minutes | int | Tighten or loosen the per-lease max TTL |
max_concurrent_leases | int | Adjust the concurrent-lease ceiling |
rotation_days | int | Update the rotation reminder interval |
Runbook: rotating a leaked OpenAI key
This runbook walks through a rotation from end to end. It assumes that cred-openai is the credential ID, and that you've already minted a new key in the OpenAI dashboard.
-
If an agent leaked the key, or may have, stop it from getting the new one: remove its grant, or disable it as in Stopping an agent from using a credential. Revoking leases isn't a step here, because a revoked lease doesn't stop an agent.
curl -X DELETE "https://api.mitrity.com/api/v1/credentials/cred-openai/grants?agent_id={agent_id}" \ -H "Authorization: Bearer mk_your-api-key" -
Update the credential value with the new key:
curl -X PUT https://api.mitrity.com/api/v1/credentials/cred-openai \ -H "Authorization: Bearer mk_your-api-key" \ -H "Content-Type: application/json" \ -d '{"credential_value":"sk-proj-NEW..."}' -
Revoke the old key in the OpenAI dashboard. This is the step that ends the leaked key: until then, every copy that was already handed out keeps working at OpenAI, the leaked one included.
-
Verify the rotation: trigger an action on an agent that still holds a grant on the credential, and confirm that it succeeds against the upstream (a normal OpenAI call returns 200). If you run the Mitrity Gateway or Mitrity MCP Sidecar, the credential resolution appears in that binary's own logs at the moment the agent acts.
The whole rotation is reversible up to step 3. If the new key has issues, you can PUT back the old value, if you still have it. After step 3, the old key is dead.
Security model
Encryption at rest
Credential values are stored with envelope encryption, using GCP Cloud KMS:
- AES-256-GCM encrypts the credential value with a per-tenant data encryption key (DEK).
- A key in Google Cloud KMS, managed in the MITRITY project, wraps (encrypts) the DEK in turn. The wrapped DEK is stored alongside the credential row.
- To decrypt, MITRITY calls Cloud KMS to unwrap the DEK, decrypts the value with the DEK, and then discards both immediately. The plaintext value never persists outside the active request scope.
- Each tenant has its own DEK, so a compromise of one tenant's wrapped DEK cannot decrypt another tenant's credentials.
Access control
- Owner, Manager and Member roles can create and update credentials, grant them to agents, and issue and revoke leases. Owner and Manager roles delete credentials and revoke grants. In the dashboard, credential management is shown to Owners and Managers.
- Viewer roles can see credential metadata (name, type, has-value flag, grant list) and change nothing. No role ever sees the secret value.
- A user whose access scope is
scopedsees every credential's metadata, but only the grants and leases of the agents granted to them. Such a user grants or leases a credential only for those agents. A credential is shared by every agent it is granted to, so creating, changing or deleting one needs full access: a scoped user gets403 Forbidden. - The secret value is released only through an edge checkout, encrypted for the agent's edge, and only while the agent holds an enabled grant on the credential that allows the operation. Whether its leases are active, expired or revoked doesn't change that.
Tenant isolation
- Every query is scoped to
tenant_id. There is no cross-tenant access path.
Limitations
The credential broker does not have these features:
- Audit events for credential management: creating, updating or deleting a credential or a grant, and issuing or revoking a lease through the API, write no audit event. Each value checkout by the edge is audited, as a
credential.checkoutevent. - Grant conditions: a grant has its allowed operations and its enabled flag, and no other condition. There is no justification, time window or environment scope.
- Lease renewal: there is no endpoint that extends an active lease. Request a new lease before the old one expires.
- Bulk revocation: no single call revokes every active lease on a credential. List the leases and revoke each one. A revoked lease is a record only; to stop agents from using a credential, remove or disable their grants.
- Drift response: an agent's drift score doesn't change which credentials it can check out. To stop an agent that behaves unexpectedly, remove or disable its grants.
- Rotation reminders:
rotation_daysis stored as metadata for your own tracking, and sends no email, Slack message or alert. - External vaults: secrets are stored only in the built-in vault. There is no GCP Secret Manager, AWS Secrets Manager or HashiCorp Vault integration.
Related documentation
- Integration Modes: how the gateway and MCP sidecar resolve leases at agent runtime
- Injection Detection: detect attempts to exfiltrate credentials via prompt injection
- Delegation Chains: credential access across delegation hops
- Agent Permissions: tool-level permissions, complementary to credential grants
- RBAC: role-based access control for credential management
- SaaS Connector Posture & Security: the separate crypto domain that protects platform-connector credentials