Client Credentials Grant
The Client Credentials grant allows a confidential client to obtain an access token on its own behalf, without any user involvement. This is designed for machine-to-machine (M2M) communication where the client itself is the resource owner.
Request
Section titled “Request”curl -X POST https://auth.example.com/oauth2/token \ -u "my-service:my-service-secret" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=client_credentials" \ -d "scope=read write"Or with client_secret_post authentication:
curl -X POST https://auth.example.com/oauth2/token \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=client_credentials" \ -d "client_id=my-service" \ -d "client_secret=my-service-secret" \ -d "scope=read write"Parameters
Section titled “Parameters”| Parameter | Required | Description |
|---|---|---|
grant_type |
Yes | Must be client_credentials |
scope |
No | Space-separated list of scopes (defaults to client’s allowed scopes, minus openid) |
client_id |
Conditional | Required if not using HTTP Basic authentication |
client_secret |
Conditional | Required if not using HTTP Basic authentication |
Response:
{ "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...", "token_type": "Bearer", "expires_in": 900, "scope": "read write"}Note the absence of id_token and refresh_token in the response. Per RFC 6749 Section 4.4.3, a refresh token SHOULD NOT be included.
Requirements
Section titled “Requirements”Client type
Section titled “Client type”Only confidential clients can use the client credentials grant. Public clients will receive an unauthorized_client error. This is enforced per RFC 6749 Section 4.4.2.
Client authentication
Section titled “Client authentication”The client MUST authenticate with the authorization server. Supported authentication methods:
client_secret_basic– client ID and secret sent via HTTP Basic authentication headerclient_secret_post– client ID and secret sent in the request body
Grant type registration
Section titled “Grant type registration”The client must have client_credentials in its grant_types:
curl -X POST https://auth.example.com/admin/api/clients \ -H "Authorization: Bearer $ADMIN_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "client_id": "my-service", "client_name": "My Background Service", "client_secret": "my-service-secret", "redirect_uris": [], "grant_types": ["client_credentials"], "response_types": [], "scopes": "read write", "client_type": "confidential", "token_endpoint_auth_method": "client_secret_basic" }'Scope handling
Section titled “Scope handling”- If no
scopeis provided, the client’s configured scopes are used - The
openidscope is automatically stripped because there is no user identity to assert - If no valid scopes remain after stripping
openid, the request fails withinvalid_scope - Requested scopes are validated against the client’s allowed scopes
Access token structure
Section titled “Access token structure”The access token is a signed JWT (RS256) with the following notable claims:
| Claim | Value |
|---|---|
sub |
The client_id (the client is the resource owner) |
azp |
The client_id |
aud |
Includes the issuer URL and any configured allowed_audiences |
scope |
The granted scopes |
Limitations
Section titled “Limitations”- No user identity – no
id_tokenis issued - No refresh token – each token must be obtained independently
- No SSO session – each grant is a standalone token issuance
- Confidential clients only – public clients cannot use this grant