Skip to content

API Keys

Security page — API keys tab with a list of issued keys, scopes, last-used timestamps, and a rotate/revoke action menu.

API keys let scripts, bots, and integrations call Agentcy without going through the user login flow. A key is org-scoped, role-bound, and accepted by the same middleware that accepts JWTs — no separate code path for clients.

Create a key

bash
curl -X POST http://localhost:8080/api/v1/api-keys \
  -H "authorization: Bearer $TOKEN" -H 'content-type: application/json' \
  -d '{
    "name":"ci-deploy-bot",
    "role":"member",
    "expires_at":"2026-10-24T00:00:00Z",
    "allowed_ips":["10.0.0.0/8"],
    "notes":"used by GitHub Actions to post chat summaries"
  }'

Response (the key is shown once):

json
{
  "id":"key_01HABC…",
  "name":"ci-deploy-bot",
  "key":"ak_live_<opaque>",
  "key_fingerprint":"ak_01HABC",
  "role":"member",
  "expires_at":"2026-10-24T00:00:00Z",
  "created_at":"2026-04-24T12:00:00Z"
}

Immediately copy key. Future reads only return the fingerprint.

Use it

bash
curl -H "authorization: Bearer ak_live_…" http://…/api/v1/chat/conversations | jq

The auth middleware:

  1. Accepts the bearer value.
  2. Matches against the api_keys table (bcrypt comparison on the secret part).
  3. Populates UserContext { api_key_id, org_id, role, … }.
  4. Sets subject.api_key_id in the Rego input so policies can distinguish.

From here on it's indistinguishable from a JWT-authed request.

Rotate

Keys are immutable. Rotation means "create a new key, switch clients, delete the old key."

bash
# 1. Create the replacement
curl -X POST http://…/api-keys -d '{"name":"ci-deploy-bot-2",…}' \
  -H "authorization: Bearer $TOKEN" -H 'content-type: application/json'

# 2. Deploy the new key to your client.

# 3. Delete the old key
curl -X DELETE "http://…/api-keys/$OLD_ID" -H "authorization: Bearer $TOKEN"

Revoke

bash
curl -X DELETE "http://…/api-keys/$KEY_ID" -H "authorization: Bearer $TOKEN"

Revocation is instant — the in-memory key cache in agentcy-auth is invalidated on delete. Any in-flight request using the revoked key continues; the next request with it fails.

List & audit

bash
# All keys in the org
curl http://…/api-keys -H "authorization: Bearer $TOKEN" | jq

# Usage stats per key
curl "http://…/api-keys/$KEY_ID/usage?days=30" -H "authorization: Bearer $TOKEN" | jq

The usage endpoint returns last-seen IP, request count by route, p95 latency. Useful for spotting stale keys to retire.

Scopes and roles

A key inherits a role (viewer, member, admin, owner). For finer scoping, use policies that inspect subject.api_key_id or subject.api_key_name:

rego
deny[msg] {
  input.subject.api_key_name == "ci-deploy-bot"
  input.action != "chat.conversation.message.create"
  msg := "ci bot can only send chat messages"
}

This way a key can be narrower than any built-in role.

IP allowlisting

allowed_ips accepts CIDR blocks. Requests from other IPs get 401. If your egress is behind NAT or a load balancer, configure TRUSTED_PROXIES so X-Forwarded-For is honored:

env
TRUSTED_PROXIES=10.0.0.0/8,127.0.0.1

Machine identities

For long-running workloads with an identity provider (AWS IAM, GCP service accounts, K8s service accounts), prefer OIDC over API keys. Exchange the workload identity for a short-lived JWT against your IdP, call Agentcy with that. API keys are meant for "keep it simple" scripts.

Gotchas

  • No SSO integration. Keys bypass SSO by design — that's their point, but it means a revoked SSO user's keys still work until an admin deletes them. Rotate proactively.
  • Keys don't expire on role change. If you demote a user whose key is admin, the key stays admin. Revoke and reissue.
  • Keys are bearer credentials. Store them in a secrets manager, not env files in git. Scrape logs for accidental logging — the auth middleware redacts bearer values but application code often doesn't.

Next

Built by AgentcyLabs. For in-house deployment or Agentcy Cloud (PaaS) access, visit agentcylabs.com.