Skip to content

OAuth2 Client Credentials Grant — Machine-to-Machine API Authentication

DodaTech Updated 2026-06-28 4 min read

In this tutorial, you will learn about OAuth2 Client Credentials Grant. We cover key concepts, practical examples, and best practices to help you master this topic.

The OAuth2 Client Credentials grant allows a client application to authenticate directly to the authorization server, receiving an access token without any user interaction.

What You'll Learn

How the Client Credentials grant works, when to use it, implementation with Python, and security considerations for machine-to-machine authentication.

Why It Matters

Many API integrations are server-to-server with no user present. A cron job fetches data, a microservice authenticates to another service, or a backend process calls an external API. The Client Credentials grant is designed for these scenarios.

Real-World Use

Stripe's API uses Client Credentials for backend integrations, GitHub Actions uses it for automated workflows, and Durga Antivirus Pro's backend services use Client Credentials to authenticate between microservices.

flowchart LR
    A["Backend Service\n(Client)"] -->|"POST /token\ngrant_type=client_credentials"| B["Authorization Server"]
    B -->|"Verify client_id + client_secret"| B
    B -->|"Access Token"| A
    A -->|"API call + Bearer token"| C["Resource Server"]
    C -->|"Data"| A
    style A fill:#dbeafe,stroke:#2563eb
    style B fill:#fef3c7,stroke:#d97706
    style C fill:#dcfce7,stroke:#16a34a

How It Works

  1. The client authenticates with its own credentials (client_id and client_secret)
  2. It sends a POST request to the token endpoint with grant_type=client_credentials
  3. The authorization server validates the credentials and issues an access token
  4. The client uses the access token to call the API

Use Cases

Scenario Why Client Credentials
Microservice A calling Microservice B No user context needed
Cron job fetching nightly reports Runs on schedule, no user interaction
Backend processing pipeline Automated data processing
Webhook delivery service Server-to-server notifications

Code Example: Client Credentials Flow

import requests

CLIENT_ID = "your-client-id"
CLIENT_SECRET = "your-client-secret"
TOKEN_URL = "https://auth.example.com/oauth/token"
API_URL = "https://api.example.com/reports"

# Step 1: Get access token
token_response = requests.post(TOKEN_URL, data={
    "grant_type": "client_credentials",
    "client_id": CLIENT_ID,
    "client_secret": CLIENT_SECRET,
    "scope": "reports:read"
})

token_data = token_response.json()
access_token = token_data["access_token"]
print(f"Got token: {access_token[:20]}... expires in {token_data['expires_in']}s")

# Step 2: Use token to call API
headers = {"Authorization": f"Bearer {access_token}"}
api_response = requests.get(API_URL, headers=headers)
print(f"API response: {api_response.status_code}")
print(api_response.json())

Expected output:

Got token: eyJhbGciOiJSUzI1... expires in 3600s
API response: 200
{"reports": [{"id": 1, "name": "Daily Summary"}]}

Code Example: Expressing Scopes

# Different scopes for different permissions
scopes = {
    "reports:read": "Read-only access to reports",
    "reports:write": "Create and modify reports",
    "users:read": "Read user data",
    "admin": "Full administrative access"
}

# Request minimal scope
response = requests.post(TOKEN_URL, data={
    "grant_type": "client_credentials",
    "client_id": CLIENT_ID,
    "client_secret": CLIENT_SECRET,
    "scope": "reports:read users:read"
})

print(f"Granted scopes: {response.json()['scope']}")

Common Mistakes

1. Using Client Credentials for User Actions

Client Credentials identifies the application, not a user. Do not use it for actions that need user context or audit trail.

2. Hardcoding Client Secrets in Source Code

Client secrets are sensitive credentials. Use environment variables or a secret manager.

3. Not Scoping Tokens Appropriately

Requesting admin scope when the service only needs reports:read violates the principle of Least Privilege.

4. Storing Access Tokens Without Expiry Check

The token will expire. Check expires_in and refresh proactively, or handle 401 responses.

5. Ignoring Token Endpoint Security

The token endpoint must be protected with HTTPS and Rate Limiting. A compromised client secret can be used to obtain tokens until rotated.

Practice Questions

  1. What grant type should you use for a server-to-server API integration?
  2. How does the client authenticate to the token endpoint?
  3. What is the purpose of scopes in Client Credentials?
  4. Why should Client Credentials not be used for user-specific actions?
  5. How do you refresh a Client Credentials token?

Answers:

  1. The Client Credentials grant (grant_type=client_credentials).
  2. Using client_id and client_secret sent in the POST body or via HTTP Basic Auth header.
  3. Scopes limit what the token can do (e.g., reports:read), following the principle of least privilege.
  4. Client Credentials identifies the application. There is no user context. User-specific actions need Authorization Code or ROPC grant.
  5. Client Credentials tokens are typically not refreshed — because no user is involved, simply request a new token when the old one expires.

Challenge: Build a microservice that authenticates to another service using Client Credentials, handles token expiry by Caching the token and requesting a new one before expiration, and implements retry logic on 401 responses.

FAQ

Can Client Credentials be used with mobile apps?

No. Mobile apps are public clients that cannot keep secrets. A client secret extracted from a mobile app can be used to obtain tokens until rotated.

What happens if a client secret is compromised?

The secret must be rotated immediately. All existing tokens obtained with the compromised secret remain valid until they expire.

Does Client Credentials support refresh tokens?

Typically no. Since no user is involved, the client requests a new token when the current one expires. Some providers issue refresh tokens for long-lived machine sessions.

How long should Client Credentials tokens live?

1 hour is standard. For high-throughput services, shorter expiry (15 minutes) reduces risk. Some providers allow configurable token lifetimes.

Is Client Credentials the same as API keys?

No. Client Credentials uses OAuth2 flow with token endpoint, scopes, and short-lived tokens. API keys are static and simpler but less flexible.

Mini Project

Build a Python service that authenticates to a mock API using Client Credentials, caches the token, automatically refreshes before expiration, and handles 401 responses by requesting a new token.

What's Next

Next, learn about the Resource Owner Password Credentials Grant for trusted first-party applications.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro