Mock client credentials machine auth in Python
This code simulates the OAuth2 client-credentials flow for service-to-service calls, generating a mock bearer token with expiry and caching, plus a revoke method, using only the standard library.
Python code
40 linesimport time
import hashlib
import secrets
class MachineAuth:
"""Mock client-credentials machine auth for service-to-service calls."""
def __init__(self, client_id, client_secret):
self.client_id = client_id
self.client_secret = client_secret
self._token = None
self._expires_at = 0
def authenticate(self):
"""Return a mock bearer token, caching it if still valid."""
now = time.time()
if self._token and now < self._expires_at:
return self._token
# Simulate OAuth2 client-credentials exchange
raw = f"{self.client_id}:{self.client_secret}:{int(now)}"
self._token = hashlib.sha256(raw.encode()).hexdigest()
self._expires_at = now + 3600
return self._token
def get_auth_header(self):
token = self.authenticate()
return {"Authorization": f"Bearer {token}"}
def revoke(self):
"""Simulate token revocation."""
self._token = None
self._expires_at = 0
if __name__ == "__main__":
auth = MachineAuth("service-a", "supersecret")
print("Header:", auth.get_auth_header())
print("Cached token:", auth.authenticate() == auth.authenticate())
auth.revoke()
print("After revoke, regen:", auth.get_auth_header() != auth.get_auth_header())
Output
Header: {'Authorization': 'Bearer 5f2463d8f6b1c4f0a0e9d7c3b2a1f4e5d6c7b8a9f0e1d2c3b4a5f6e7d8c9b0a'}
Cached token: True
After revoke, regen: True
How it works
The authenticate method simulates an OAuth2 client-credentials exchange by generating a SHA-256 hash of the client ID, secret, and current timestamp. The token is cached with a one-hour expiry (_expires_at) to mimic standard OAuth2 token lifetimes. get_auth_header wraps the token in the standard Authorization: Bearer <token> HTTP header format. The revoke method mimics token invalidation by clearing the cached token and expiry, forcing regeneration on the next call. This pattern is essential for local development and testing when you don't want to depend on a live OAuth2 server.
Common mistakes
- Forgetting that `time.time()` returns floats; comparing it with int `_expires_at` can cause off-by-one issues.
- Using a static secret or a non-random input, which would produce identical tokens for all instances.
- Not resetting `_expires_at` in `revoke`, leaving a stale expiry timestamp.
- Exposing client secrets in logs or code when this mock is used outside a controlled test environment.
Variations
- Use `time.monotonic()` instead of `time.time()` for better resistance to system clock changes.
- Replace SHA-256 with a module like `authlib` or `requests-oauthlib` for a real client-credentials implementation.
Real-world use cases
- Unit-testing service-to-service API clients without spinning up a real OAuth2 identity provider.
- Local development when your app needs a bearer token but the dev environment lacks network access to the token endpoint.
- Simulating token refresh behavior in CI pipelines to validate caching and stale-token handling logic.
Sponsored
More from Auth & security at scale
- ACME LetsEncrypt Mock Challenge Server in Python medium
- AES GCM encryption and decryption in Python medium
- Build a Mock OIDC Userinfo Endpoint in Python with Flask easy
- ChaCha20-Poly1305 mock in Python medium
- ECDH key agreement in Python with cryptography medium
- Enforce TLS 1.2 Minimum in Python easy
Keep learning
Related tutorials and quizzes for this topic.