Skip to content

API Keys and Service Accounts

API keys and service accounts support machine-to-machine access. They should be used only when an interactive user session is not appropriate.

API keys are tied to platform access and should be treated as secrets. An API key acts on behalf of the user who created it, limited to the scopes chosen at creation, so it is sometimes called a user API key. Use them for integrations that act with a defined platform identity.

  • Empty scopes keep legacy unrestricted behavior, in which the key impersonates the user. They do not enroll gateway agents.
  • Named scopes are RBAC permission names the creator can grant (for example register_agents, view_project_data), plus did:read when the caller is not a pure agent operator. A scoped key is deny-by-default outside that list. revoke_agents and restore_agents are never accepted as scopes, because a key cannot act as a platform admin.
  • * is explicit full access, available to organization owners only.
  • projectId binds project-level permissions to one project. Organization-level actions such as register_agents still apply across the organization. Omit projectId (All projects) for every project the holder can already access.
  • API keys cannot create or revoke API keys. Create keys with a user session.
  • Name, description, and expiry are required at create time. expiresAt must be in the future and no more than 365 days out; a key with a passed expiry reports status expired even though it is still stored as active.

A project binding must be paired with named scopes. Sending projectId with empty scopes, or with *, is rejected at create time: neither one names the organization-level actions the binding cannot take away, so the binding would advertise a narrower reach than the key actually has. Naming those scopes explicitly is still accepted — register_agents alongside a projectId is a deliberate choice, not an accident.

For enrollment, a key with register_agents or * may call the gateway with Authorization: Bearer ak_…. Both the key scope and the owner’s RBAC grant are required, and empty-scope keys cannot enroll. Create the key from Governance Studio (User ProfileAPI Keys) or the Auth Service API using a user session.

In Governance Studio, the create dialog requires at least one named scope and no longer offers Full access (*). An organization owner who needs full access can still send "scopes": ["*"] to the Auth Service API. Choosing Project access hides the scopes a binding cannot narrow — organization-level actions and did:read — so switch to Organization to include them.

Recommended practices:

  • Store keys in a secrets manager.
  • Prefer a short expiry and one key per agent or pipeline.
  • Rotate keys when ownership or system responsibility changes.
  • Revoke unused keys. Revoking a key does not unwind agents already enrolled with it, and an API key cannot revoke or restore an agent regardless of its scopes — that action requires a signed-in organization owner.
  • Avoid sharing a single key across unrelated integrations.

The Integrity Service accepts Authorization: Bearer ak_… on every route, so the Python SDK (eqty_sdk) and other integrations can sign with an auth-service signer and register lineage with one key and no user session. Each route is attributed to a project and checked against the key’s scopes and binding through Auth Service RBAC.

  • Registering a graph, statement, or blob under a project needs create_declarations on that project, and view_project_data to read it back. Bind the key to the project when the integration only ever writes to one. Registering a new project root needs create_projects, which is organization-level.
  • A key writing outside its binding, or without the permission, gets 403 Forbidden naming the permission it lacks. An unregistered graph ID is also a 403 on writes, so a key cannot probe for graph IDs.
  • GET /graph/v1 lists only the project trees the key can view. A key with no view_project_data anywhere gets an empty list rather than an error.
  • PUT /dynamic-config/v1 (manage_org_settings) stays user-session only.
  • If Auth Service is unreachable while a check runs, the request is refused with 503 Service Unavailable; retry it. A 403 is a policy decision and will not change on retry.

A typical SDK key for a pipeline is create_declarations plus view_project_data, bound to the project, with a short expiry. GET /api/v1/rbac/permission/{permission}/projects on the Auth Service reports the projects where a key or user holds a permission, after scopes and binding are applied, which is useful for checking a key before handing it to a pipeline.

The Guardian control plane accepts Authorization: Bearer ak_… on the routes that ask Auth Service RBAC for a permission. Unlike the Integrity Service, it does not accept keys everywhere: a route that is gated on identity alone still requires a user session.

  • Minting an agent registration token needs register_agents, so a headless Viper enrollment can use a key instead of a Governance Studio login.
  • The project-scoped agent, trust, and membership routes are checked against the key’s scopes and binding for that project.
  • GET /v1/agents requires project_uuid when it is called with a key, so the same view_project_data check applies and the results are limited to that project.
  • A key never acts as a platform admin, even when its owner is one. Admin-only routes — creating or revoking agents, managing plugin secrets, and listing users — return 403 Forbidden for any key.
  • Routes gated on identity alone (/v1/me, /v1/blobs/…, per-agent reads, plugin catalog and configuration reads) also refuse keys with 403 until each is mapped to a permission. Use a user session or JWT for those.

Service accounts are for trusted platform services, such as backend workers that need to call another platform service. Operators configure service accounts as part of deployment and operations.

Do not use service accounts for normal human user access. Human users should sign in through the identity provider and receive project roles.

Use a user API key when the integration should be accountable to a user or customer-managed integration identity. Use a service account when the integration is a platform service that must operate independently of a human user.