Client credentials grant for machine-to-machine: when it fits agents

Your agent needs to call an API, but there’s no user to authorize. No browser redirect, no “enter this code” screen — just a service talking to a service. That’s the machine-to-machine case, and OAuth has a dedicated flow for it: the client credentials grant (RFC 6749 §4.4). It’s simple, but “simple” doesn’t mean “safe” — and it fits agent workloads far less often than people assume.

What client credentials grant is

The flow is short: the client sends its own client_id and client_secret to the token endpoint and receives an access token. No user, no authorization code, no refresh token in most implementations — the client authenticates as itself, and the token represents the client’s own identity. The provider issues it with whatever scopes the client is registered for.

That makes it attractive for automation: CI pipelines, cron jobs, background sync, and agent tooling all run unattended, and the grant has no interactive step.

Where it fits

Client credentials work when the caller’s identity is the whole story:

  • internal services calling your own APIs
  • batch jobs whose permissions don’t depend on a human
  • infrastructure tooling where the service account maps cleanly to one tenant or one scope set

If the answer to “who is acting here?” is “this application, full stop,” the grant fits.

Where it doesn’t fit

The moment you need per-user data, delegation, or audit attribution, client credentials is the wrong tool. If the API returns different data depending on which human is asking, the token must carry user context — which means an authorization code or device flow, not client credentials. Two agents sharing one client secret also become indistinguishable in logs: you can’t tell which agent did what, and revoking one agent means rotating the shared secret and breaking both. Per-agent client IDs are the minimum for any attribution.

Practical pitfalls

  • The secret is the credential. The client secret is a static, long-lived bearer credential. Anyone who reads it can mint tokens. It belongs in a secret store, not in a config file or an agent’s environment.
  • Scope creep at registration. Providers often grant everything the client registers for. Narrow the registered scopes at the provider, not at call time.
  • Rotation is on you. With no refresh token, you rotate the secret yourself — and every place it was copied becomes a leak.

The agent-specific problem

For AI agents there’s an extra wrinkle: the agent’s context window is a conduit for secrets. If the client secret or a minted token passes through the agent’s tool output, a prompt injection can exfiltrate it. The fix is structural — keep the credential out of the agent’s sight entirely. A credential broker like https://github.com/ikkun1222/trustless reads from an existing pass or Bitwarden store and injects the secret into the subprocess environment only when the agent’s tool actually runs, via trustless run -s <key> -- <cmd>.

Client credentials grant is the right flow for service-to-service automation with a stable identity and narrow scopes. For anything that needs user context, reach for a flow with a user in it — and in both cases, make sure the agent never handles the credential itself.

Is the identity behind your agent’s API calls the application or the user — and does your current setup reflect that?