Skip to content

OAuth 2.0 Client Credentials — Complete Server-to-Server Auth Guide

DodaTech Updated 2026-06-28 2 min read

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

The client credentials grant is an OAuth 2.0 flow for machine-to-machine communication. The client authenticates using its own credentials (client_id and client_secret) and receives an access token without any user involvement.

What You'll Learn

You'll learn how client credentials work, when to use them, and how to implement secure service-to-service authentication.

Why It Matters

Microservices need to authenticate to each other. Client credentials provide a standardized, secure way for services to obtain tokens without user context.

Real-World Use

A background job service uses client credentials to authenticate to the main API. Every 15 minutes, it obtains a new token to Process pending tasks, with no user interaction required.

sequenceDiagram
    participant ServiceA as Backend Service
    participant Auth as Authorization Server
    participant API as Protected API
    ServiceA->>Auth: POST /token (client_id, client_secret, scope)
    Auth->>ServiceA: access_token
    ServiceA->>API: GET /data (Bearer token)
    API->>Auth: Validate token (optional introspection)
    Auth-->>API: Token valid
    API->>ServiceA: Data

Teacher's Mindset

Client credentials are like a company badge that gives you access to the server room. The badge identifies you as an employee (not a specific person) and grants machine-level permissions.

Implementation

from flask import Flask, request, jsonify
import jwt
from datetime import datetime, timedelta
import secrets

app = Flask(__name__)

CLIENTS = {
    "batch-processor": {"secret": "hashed-secret-1", "scopes": ["jobs:read", "jobs:write"]},
    "report-generator": {"secret": "hashed-secret-2", "scopes": ["reports:read"]}
}

@app.route("/oauth/token", methods=["POST"])
def token():
    client_id = request.form.get("client_id")
    client_secret = request.form.get("client_secret")
    scope = request.form.get("scope", "")
    grant_type = request.form.get("grant_type")
    if grant_type != "client_credentials":
        return jsonify({"error": "unsupported_grant_type"}), 400
    client = CLIENTS.get(client_id)
    if not client or client["secret"] != client_secret:
        return jsonify({"error": "invalid_client"}), 401
    token = jwt.encode({
        "sub": client_id,
        "scope": scope,
        "iat": datetime.utcnow(),
        "exp": datetime.utcnow() + timedelta(hours=1)
    }, "secret-key", algorithm="HS256")
    return jsonify({
        "access_token": token,
        "token_type": "Bearer",
        "expires_in": 3600,
        "scope": scope
    })
# Client-side usage
def call_protected_api():
    response = requests.post(
        "https://auth.example.com/oauth/token",
        data={
            "grant_type": "client_credentials",
            "client_id": "batch-processor",
            "client_secret": "your-secret",
            "scope": "jobs:read jobs:write"
        }
    )
    access_token = response.json()["access_token"]
    headers = {"Authorization": f"Bearer {access_token}"}
    result = requests.get("https://api.example.com/jobs", headers=headers)
    return result.json()

Common Mistakes

Mistake Fix
Hardcoding client secrets in code Use environment variables or vault
No scope restriction Limit tokens to minimum required scopes
Long token lifetimes Keep tokens under 1 hour for services
No token revocation Maintain token blacklist or short expiry
Client credentials for user delegation Use authorization code for user context

Practice Questions

  1. When should you use client credentials vs authorization code?
  2. How do scopes limit access in client credentials?
  3. Why is client credentials unsuitable for user-facing apps?
  4. How do you rotate client secrets?
  5. What is token introspection?

Challenge

Implement a client credentials server and two microservices. Service A uses client credentials to obtain a token and call Service B. Service B validates the token and checks scopes.

What's Next

Learn about OAuth 2.0 PKCE for secure mobile and SPA authentication.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro