Skip to main content

Client Credentials

RFC 6749 §4.4

Client type: Confidential clients acting on their own behalf (no user involved) – machine-to-machine (M2M)

The Client Credentials grant issues tokens to applications acting on their own behalf, not on behalf of a user. A service authenticates with its client_id and client_secret to get an access token. No user authorization UI involved. Standard for microservice-to-microservice API calls, batch jobs, background workers, and CI/CD pipelines calling APIs.

How it works

Client Credentials is the machine-to-machine (M2M) grant type. There is no user, no authorization UI, no redirect.

Flow (two steps total): 1. Client POSTs client_id, client_secret, grant_type=client_credentials, scope to /token 2. Authorization server returns access_token (no refresh_token – client can just re-authenticate)

No refresh token: since the client can authenticate at any time (it has its credentials), there is no need for a refresh token in Client Credentials. Just request a new access token when the current one expires.

Use cases: - Service A calls Service B's API: Service A authenticates with its own credentials - GitHub Actions calling a protected API - Cron jobs and batch processors - CI/CD pipelines deploying to cloud APIs - Microservice mesh authentication (often replaced by mTLS in service meshes)

Scopes in M2M: scopes still apply to restrict what the service can access. A reporting service should only have read scopes, not write scopes, even for M2M tokens.

Client secret security: client secrets must be stored securely (environment variables, secrets manager). Rotate them regularly. Consider using private_key_jwt authentication (RFC 7523) instead of client_secret for higher-security environments.

Flow Steps

  1. 1

    Client POSTs to /token with grant_type=client_credentials, client_id, client_secret, scope

  2. 2

    Authorization server validates credentials and issues access_token

  3. 3

    Client uses access_token in Authorization: Bearer header for API calls

  4. 4

    On expiry (expires_in), client requests a new token directly (no refresh token needed)

Parameters

ParameterRequiredDescription
grant_typeYesMust be 'client_credentials'
client_idYesApplication/service identifier
client_secretYesApplication/service secret. Can also use client_assertion (JWT) for higher security.
scopeNoRequested scopes for the token. Principle of least privilege.

Examples

Client Credentials token request
# Service-to-service authentication
POST https://auth.example.com/oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials
&client_id=svc_payment
&client_secret=secret_abc123
&scope=orders:read invoices:write

# Response (no refresh_token)
{
  "access_token": "eyJhbGciOiJSUzI1NiIs...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "scope": "orders:read invoices:write"
}

# Use token for API call
curl -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..." \
  https://api.example.com/orders

When to use

Any machine-to-machine communication where there is no user: microservices, batch jobs, CI/CD pipelines, background workers, scheduled tasks calling external APIs.

See Also