Skip to content

Client Credentials Flow

The Client Credentials flow is designed for server-to-server authentication where no user is involved. The client (your application) authenticates directly with the authorization server using its own credentials to obtain an access token.

Use the client credentials flow when:

  • Backend services need to communicate with each other
  • Scheduled jobs or cron tasks need to access APIs
  • Microservices need to authenticate with other services
  • Daemons or background workers need API access
  • Any scenario where no user is involved in the authorization

The client credentials flow is straightforward:

  1. Your service sends a token request to the authorization server’s /auth/token endpoint, including the client ID, client secret, and requested scopes
  2. The auth server validates the credentials and returns an access token
  3. Your service uses the token to authenticate when calling other APIs

Make a POST request to the token endpoint with your client credentials.

ParameterRequiredDescription
grant_typeYesMust be client_credentials
client_idYesYour client identifier
client_secretYesYour client secret
scopeYesSpace-separated list of resource:permission scopes

You can provide client credentials in two ways:

Terminal window
curl -X POST https://auth.example.com/auth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=my-service" \
-d "client_secret=my-secret" \
-d "scope=product-api:read product-api:write"
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "product-api:read product-api:write"
}

Note that:

  • No refresh token is issued for client credentials flow
  • No ID token is issued (there’s no user to identify)
  • You should request a new token before the current one expires

Include the access token in the Authorization header when calling protected APIs:

Terminal window
curl -X GET https://api.example.com/products \
-H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."
  1. Navigate to Clients → Add Client in the admin console
  2. Set Client type to Confidential (required for client credentials)
  3. Enter a Client identifier (e.g., my-backend-service)
  4. Go to OAuth2 flows and enable Client Credentials
  5. Note your Client ID and Client Secret

The client credentials flow uses resource:permission scopes. To set this up:

  1. Create a Resource (Settings → Resources → Add Resource)
    • Example: product-api
  2. Add Permissions to the resource
    • Example: read, write, delete
  3. Assign permissions to your client (Clients → [Client] → Permissions)
    • Check the permissions the client should have

The client can then request these scopes:

scope=product-api:read product-api:write

Error responses follow RFC 6749 Section 5.2 and include cache prevention headers:

Cache-Control: no-store
Pragma: no-cache
ErrorHTTP StatusDescription
invalid_client401Client authentication failed (wrong ID or secret)
invalid_scope400Requested scope is invalid or not allowed for this client
unauthorized_client400Client is not authorized for client_credentials grant
invalid_request400Missing required parameter

For invalid_client errors, a WWW-Authenticate: Basic header is included when HTTP Basic authentication was used.

HTTP/1.1 401 Unauthorized
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache
WWW-Authenticate: Basic
{
"error": "invalid_client",
"error_description": "Client authentication failed. Please review your client_secret."
}
  1. Protect client secrets - Store secrets in environment variables or secret management systems, never in code
  2. Use minimal scopes - Only request the permissions your service actually needs
  3. Rotate secrets regularly - Periodically regenerate client secrets and update services
  4. Monitor token usage - Log and monitor API calls to detect unusual patterns
  5. Use short token lifetimes - Configure appropriate expiration times for your use case
  6. Network security - Restrict which networks can access the token endpoint if possible
  7. Don’t share credentials - Each service should have its own client credentials

When your API receives a token from another service, validate it:

  1. Verify the signature using the authorization server’s public keys (JWKS endpoint)
  2. Check the issuer (iss) matches your authorization server
  3. Verify the audience (aud) includes your API’s resource identifier
  4. Check expiration (exp) to ensure the token hasn’t expired
  5. Validate scopes to ensure the token has the required permissions

See the Tokens documentation for more details on token validation.