API Keys and Service Accounts
Machine authentication with API keys, and how service accounts for backend workers are set up.
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
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), plusdid:readwhen the caller is not a pure agent operator. A scoped key is deny-by-default outside that list.revoke_agentsandrestore_agentsare never accepted as scopes, because a key cannot act as a platform admin, and neither iscertify_agents, which belongs to the governance worker service account alone. *is explicit full access, available to organization owners only.projectIdbinds project-level permissions to one project. Organization-level actions such asregister_agentsstill apply across the organization, exceptview_agent_certifications,submit_agent_assessmentsandreview_agent_assessments, which a project-bound key cannot carry. OmitprojectId(Organization) for every project the holder can already access.- API keys cannot call any
/api/v1/api-keysroute, so a key cannot create, list, read, or revoke keys. Manage keys with a user session. allowedIpslimits the key to the listed IP addresses or CIDR ranges, matched against the address Auth Service sees the request come from.- Name, description, and expiry are required at create time.
expiresAtmust be in the future and no more than 365 days out; a key with a passed expiry reports statusexpiredeven 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. The exceptions are view_agent_certifications, submit_agent_assessments and review_agent_assessments: each is refused alongside a projectId, because agents’ certifications and assessments are served only to a key bound to no project.
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 Guardian (Settings → API Keys) or the Auth Service API using a user session.
In Guardian, 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.
Integrity Service and the SDK
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 or statement under a project needs
create_declarationson that project, andview_project_datato read it back. Bind the key to the project when the integration only ever writes to one. Registering a new project root needscreate_projects, which is organization-level. - Storing a blob needs
create_declarationsorcreate_commentsin any project the key reaches, and reading one needsview_project_datain any project. - A key writing outside its binding, or without the permission, gets
403 Forbiddennaming the permission it lacks. An unregistered graph ID is also a403on writes, so a key cannot probe for graph IDs. GET /graph/v1lists only the project trees the key can view. A key with noview_project_dataanywhere 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. A403is 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. Send the key as a bearer token:
curl "https://guardian.example.com/authService/api/v1/rbac/permission/create_declarations/projects" \
-H "Authorization: Bearer $GUARDIAN_API_KEY"{
"permission": "create_declarations",
"projects": [{ "id": 15, "uuid": "fd47f68b-8760-4d0d-94fa-7658924acb25" }]
}An empty projects list means the key cannot use that permission anywhere.
Governance Service
The Governance Service checks a key’s scopes and binding through Auth Service RBAC, as it checks a person’s permissions. The routes that act on who a person is to a program or an assessment accept a key bound to no project that has empty scopes or *, or the scope for that standing:
submit_agent_assessments: start an assessment, and pin, declare, claim controls not applicable in and submit one the key’s holder started.review_agent_assessments: review a control of an assessment of a program the holder reviews, ask again for a certification their review rests on, and revoke one they authorized.manage_programs: assign and remove a program’s reviewers, revoke any certification, and ask again for any certification except one of an assessment the holder started or a submission they made.
A scope counts only while the holder still holds that permission in the organization, and their standing still decides, as it does for their sign-in. Assigning a reviewer looks the member up in Auth Service with the key, which only a key with empty scopes or * may do. Signing a certification with the platform key takes a key whose scopes cover every permission of a role that may sign.
Control Plane
The 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: most routes gated on identity alone still require a JWT. Control Plane Authentication and RBAC covers the permission each route checks.
-
Minting an agent registration token needs
register_agents, so a headless Viper enrollment can use a key instead of a Guardian sign-in. -
The project-scoped agent, trust, and membership routes are checked against the key’s scopes and binding for that project.
-
GET /v1/agentsrequiresproject_uuidwhen it is called with a key, so the sameview_project_datacheck applies and the results are limited to that project. Filtering it withhas_profile=truealso needs a key that could read those profiles: one bound to no project, with empty scopes,*orsubmit_agent_assessments. Any other key gets403 Forbidden. -
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 Forbiddenfor any key. -
Per-agent routes under
/v1/agents/{id}accept a key bound to no project that has empty scopes or*, which acts as its holder there, or the scope for what the route does, for the agents its holder is bound to:submit_agent_assessmentsreads the agent: its detail, configurations, state history and the files a state references, definitions, tools and operating profile.view_agent_certificationsreadsGET /v1/agents/{id}/certifications, so deploy automation can pull an agent’s certifications.manage_programsorreview_agent_assessmentsattach a certification, as the Governance Service does for whoever asked for it.
A scope counts only while the holder still holds that permission in the key’s organization: Auth Service validation reports those as
keyHeldScopes, beside thekeyScopesthe key was created with, and the Control Plane acts on nothing else. A state’s raw snapshot and findings, audit exchanges, plugin events and saving an agent’s profile take empty scopes or*. A project-bound key, or one without the route’s scope, gets403 Forbidden. -
Other routes gated on identity alone (
/v1/me, plugin catalog and configuration reads) refuse keys with403until each is mapped to a permission. Use a JWT for those.
Service Accounts
Service accounts are for trusted platform services, such as backend workers that call another platform service, and for approved backend integrations. Operators configure service accounts as part of deployment and operations, not as an ad hoc user workflow.
Do not use service accounts for normal human user access. Human users should sign in through the identity provider and receive project roles.
Setting Up Service Accounts
Auth Service creates one service account, governance-worker, at startup from the provider’s client credentials:
- Auth0:
AUTH0_GOVERNANCE_WORKER_CLIENT_IDandAUTH0_GOVERNANCE_WORKER_CLIENT_SECRET, plusAUTH0_GOVERNANCE_WORKER_AUDIENCE(defaults toIDP_AUTH0_API_IDENTIFIER). - Keycloak:
KEYCLOAK_GOVERNANCE_WORKER_CLIENT_IDandKEYCLOAK_GOVERNANCE_WORKER_CLIENT_SECRET. Without a secret, Auth Service creates the client in Keycloak. - Microsoft Entra:
ENTRA_GOVERNANCE_WORKER_CLIENT_IDandENTRA_GOVERNANCE_WORKER_CLIENT_SECRET, plusENTRA_GOVERNANCE_WORKER_SCOPE.
The chart sets these from global.secrets.governanceWorker while auth-service.config.serviceAccounts.governanceWorker.enabled is true (the default). Missing credentials or a failed creation is only logged, and Auth Service still starts, so check its startup logs. A platform service gets the account’s token from GET /api/v1/service-accounts/governance-worker/token, authenticated with API_SECRET as a bearer token.
After setup, confirm the service account can perform only the workflow it was created for. If a service account fails, check its configured secret, service name, role expectations, and Auth Service health.
Store service-account credentials in the deployment secret system. Do not reuse service-account secrets across unrelated integrations, and rotate credentials after suspected exposure. To rotate the governance worker’s secret, issue a new one in the identity provider, update platform-governance-worker, and restart Auth Service, which stores the configured secret at startup.
Choosing Between Them
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.
Related
- API Keys — generating, scoping, and revoking keys in Guardian
- RBAC and Membership — the role permissions a key’s scopes are drawn from
- Register Agents — enrolling a gateway agent with a key
- Token Flows — how keys compare with the other credential flows
- Authentication and Authorization Guidelines — storage and rotation practices for keys and service-account secrets