API Key Endpoints

Manage tenant API keys for server-to-server authentication.


Create API Key

POST /api/v1/api-keys

Headers

  • Authorization: Bearer <adminToken>
  • X-Bulwark-Tenant: <tenant-id>
  • X-Bulwark-App-Id: <app-id> — Optional. Scopes the API key to a specific application.

Body

{
  "name": "mimir-runtime",
  "scopes": ["fga:read", "fga:write"],
  "expiresAt": "2027-01-01T00:00:00Z"
}

scopes is validated against the server's scope registry and is required — at least one scope must be supplied. Unknown scope strings return 400 Bad Request with the offending scope(s) named in the error.

Response 201

{
  "data": {
    "keyId": "key_01j...",
    "name": "mimir-runtime",
    "key": "bwk_live_...",
    "scopes": ["fga:read", "fga:write"],
    "expiresAt": "2027-01-01T00:00:00Z",
    "createdAt": "2026-03-18T00:00:00Z"
  }
}

Important: The key value is only returned once. Store it immediately.


List API Keys

GET /api/v1/api-keys

Response 200

{
  "data": [
    {
      "keyId": "key_01j...",
      "name": "mimir-runtime",
      "scopes": ["fga:read", "fga:write"],
      "lastUsedAt": "2026-03-18T12:00:00Z",
      "expiresAt": "2027-01-01T00:00:00Z",
      "status": "active"
    }
  ]
}

Key values are never returned after creation.


List Available Scopes

GET /api/v1/api-keys/scopes

Returns the registry of valid scope strings, grouped for display. Use this to populate scope pickers in tooling so callers cannot fat-finger a scope name into a key that silently fails.

Response 200

{
  "scopes": [
    {
      "name": "fga:read",
      "group": "FGA",
      "description": "Read authorization tuples and run check / filter / list-objects queries."
    },
    {
      "name": "fga:write",
      "group": "FGA",
      "description": "Write and delete authorization tuples. Implies fga:read for evaluation."
    }
  ]
}

Revoke API Key

DELETE /api/v1/api-keys/{keyId}

Immediately invalidates the key.

Response 200

{
  "data": {
    "keyId": "key_01j...",
    "status": "revoked",
    "revokedAt": "2026-03-18T13:00:00Z"
  }
}

Available Scopes

The set of scopes the server will accept is the source of truth at GET /api/v1/api-keys/scopes. Today:

| Scope | Group | Description | | ------------- | ----- | ------------------------------------------------------------------------ | | fga:read | FGA | Read authorization tuples and run check / filter / list-objects queries. | | fga:write | FGA | Write and delete authorization tuples. Implies fga:read for evaluation. | | users:read | Users | List and fetch users in the workspace (admin read access). | | users:write | Users | Create, update, and delete users. Required for programmatic user provisioning (e.g. invitation-accept flows). | | vault:read | Vault | List configured services in the vault registry. Does NOT expose stored secret values — those are vended through credential.Service.Vend with policy enforcement. | | vault:write | Vault | Store encrypted secrets and upsert service configs. Required for programmatic vault provisioning (CI seeding, deployment scripts). |

Other Bulwark surfaces (agents, audit, webhooks) do not yet enforce scopes — those endpoints currently authenticate via JWT only and ignore key scopes. Scope-based auth rolls out incrementally; this page and the scopes endpoint reflect what the server enforces today.