Client Credentials
The Client Credentials grant (RFC 6749 §4.4) is the machine-to-machine flow. A backend service authenticates with its own credentials at the token endpoint and receives an access token that represents the service itself, with no user context, no redirect, and no browser.
Use it for service-to-service calls, internal daemons, scheduled jobs, and CLI tools that act under a system identity rather than on behalf of a user.
How It Works
How ThunderID Implements It
| Aspect | Behavior |
|---|---|
| Endpoint | POST /oauth2/token |
| Grant type | client_credentials |
| Client type | Intended for confidential clients that authenticate with their own credentials |
| Token subject | sub in the issued access token is the client_id |
| User attributes | Not included: there is no authenticated user |
| Refresh token | Not issued for this grant (re-request when needed) |
| Scope filtering | Requested scopes are filtered to permissions defined on the target resource server, then intersected with the permissions the client holds through its role and group assignments |
aud claim | The supplied resource server identifier, or defaultResourceServer for a permission-bearing request without resource. A scopeless request without resource uses the application's token.accessToken.defaultAudience, falling back to client_id |
| ID token | Not issued: this is an OAuth-only flow, not OIDC |
Try It in ThunderID
- Console
- Dynamic Client Registration
- Open Applications or Agents in the ThunderID Console and select your client.
- Open the Advanced Settings tab.
- Under Grant Types, select
client_credentials. - Choose a confidential Token Endpoint Authentication method (see Client Authentication Methods).
- Assign the roles or groups that grant the permissions the service should hold: these determine the scopes it can be issued.
- Save.
note
When requesting permission scopes, the client must include resource unless defaultResourceServer is configured globally. A scopeless request does not require either setting and uses the application's token.accessToken.defaultAudience (falling back to client_id) as its audience.
POST /oauth2/dcr/register
Content-Type: application/json
{
"client_name": "Billing Service",
"grant_types": ["client_credentials"],
"token_endpoint_auth_method": "client_secret_basic",
"scope": "reservations:create reservations:view"
}
Request a Token
curl -X POST https://thunderid.example.com/oauth2/token \
-u "$CLIENT_ID:$CLIENT_SECRET" \
-d "grant_type=client_credentials" \
-d "scope=reservations:create" \
-d "resource=https://api.example.com/booking"
Response:
{
"access_token": "eyJhbGciOiJSUzI1NiI...",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "reservations:create"
}
Related Guides
- Client Authentication Methods, required for confidential clients
- Resource Indicators, target the token at a specific resource server
- Token Exchange, exchange a service token for a downscoped or audience-restricted one
- Token Introspection, let resource servers validate the token