Pick one non-human identity. Do not stack them for the same workload.
| Use this | When | Where |
|---|---|---|
| M2M application | The whole project is a backend, job, or CI workload. No human users in that project. | Projects → Machine-to-machine |
| Agents entry | A named AI agent or workload calls APIs or MCP tools inside an existing project. You need verify, revoke, allowed tools, and activity. The console module is sales-gated (agents) — request access if the page is locked. |
Agents |
| Service account | Organization-owned automation managed through the Authdog REST API, not the console Agents module. | GET/POST/DELETE /v1/service-accounts |
| Personal access token | One person's local script or developer tool. Lifecycle stays attached to that person. | GET/POST /v1/personal-access-tokens |
Agents are not users. Never put a human cookie or personal token in an unattended runtime.
Machine-to-machine application
Use an M2M application when a workload must authenticate without a person: backend-to-backend calls, jobs, or CI. Authdog registers a confidential OIDC client for the environment and uses OAuth 2.0 client_credentials. No browser session.
Create an M2M application
In the Authdog console:
- Create a new project or application.
- Choose Machine-to-machine as its type.
- Enter a descriptive name and, optionally, what the workload will access.
- Create the application.
- Copy the generated client ID and client secret before closing the dialog.
Creation provisions a default environment and registers a client authorized only for client_credentials, using client_secret_basic. The client secret is shown once.
Use a separate M2M application per workload and environment so one compromise does not rotate unrelated automation.
Discover the token endpoint
Read token_endpoint from the environment's OIDC metadata. Authdog's token path is /oauth2/token. Discovery keeps working with a custom domain.
Exchange credentials for a token
curl -X POST "$TOKEN_ENDPOINT" \
-u "$AUTHDOG_CLIENT_ID:$AUTHDOG_CLIENT_SECRET" \
-H "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "grant_type=client_credentials"Successful responses contain access_token, token_type (Bearer), expires_in, and scope client_credentials. expires_in comes from the registered client's access-token lifetime. No refresh token — repeat the exchange before expiry.
Call a protected service
Authorization: Bearer <access_token>The receiving service must validate the token, then enforce authorization. A valid machine token identifies a caller; it does not grant every action.
If application creation succeeds but credential generation fails, create or inspect the client under Authentication > Clients.
Agents (named workloads)
When the caller is an AI agent (or a workload you want to verify, scope, and revoke independently of the project type), register it in Agents. The console module is sales-gated until access is approved.
Create new agent identity provisions a confidential OIDC client the same way M2M does, then writes a trust-store entry whose subject is that client ID. Register existing identity attaches an existing client ID, SPIFFE ID, or URI.
Revoke in Agents is the issuer kill switch when the subject is the OIDC client_id: new tokens fail. SPIFFE or URI subjects stay in the registry for AuthZEN; they do not stop token mint. Outstanding JWTs remain valid until expires_in unless the resource server runs trust-store enforce. Pin the tool manifest if the agent talks to MCP — the hash is reviewable; it is not a live rug-pull detector.
Public REST still lives under the trust-store path:
/v1/tenants/{tenantId}/environments/{environmentId}/mcp/trust-storeList, create, verify, revoke, and manage keys there. Console GraphQL (mcpTrustStoreEntries and related mutations) is what the Agents module calls.
Service accounts
Service accounts represent organization-owned automation with explicit scopes. They are a separate REST resource, not rows in Agents.
GET /v1/service-accountsGET /v1/service-accounts/{id}POST /v1/service-accountsDELETE /v1/service-accounts/{id}
Create with a descriptive name, optional description, and least-privilege scopes. The create response includes clientId and clientSecret. Capture the secret once. Deleting the account is the revocation path.
Personal access tokens
A PAT delegates the current user's access to scripts and developer tooling. Do not use it for shared services.
GET /v1/personal-access-tokensPOST /v1/personal-access-tokensPOST /v1/personal-access-tokens/{id}/revoke
Create accepts name, optional expiresAt, and optional scopes. Only create returns fullToken. Set an expiry and revoke when the task ends or the owner leaves.
Security guidance
- Store client secrets in a secret manager, never source control, browser code, command history, or logs.
- Keep token exchange in trusted workloads.
- One client (or Agents entry) per workload. Least privilege on scopes and tools.
- Cache access tokens only in memory, only until shortly before
expires_in. Add jitter when many instances refresh. - On suspected exposure, revoke or replace credentials. Do not wait for leaked access tokens to expire.
- Record client ID and workload name in audit context. Redact secrets and complete tokens.
- Test
devandprodindependently. Clients and signing context are environment-scoped.
The token endpoint rejects inactive or unknown clients, incorrect authentication methods, bad secrets, clients not authorized for client_credentials, and revoked machine identities.
Related
- Agents: register, verify, and revoke named agent identities
- MCP servers: playground and MCP project type
- Backend requests: accepting machine tokens
- Sessions and tokens: token model
- Authorization: enforcing access after authentication
- Deployments: environment isolation
- Security: key and credential guidance