JWT Service-to-Service Authentication Mock in Python
Create and verify HS256 JWTs for service-to-service authentication without external libraries.
Python code
57 linesimport hashlib
import hmac
import base64
import json
import time
class JWTMock:
"""Minimal JWT service-to-service mock using HS256."""
def __init__(self, secret):
self.secret = secret.encode()
@staticmethod
def _b64url_encode(data):
return base64.urlsafe_b64encode(data).rstrip(b'=').decode()
@staticmethod
def _b64url_decode(data):
padding = '=' * (-len(data) % 4)
return base64.urlsafe_b64decode(data + padding)
def create_token(self, service_name, audience, ttl_seconds=3600):
header = {"alg": "HS256", "typ": "JWT"}
payload = {
"iss": service_name,
"sub": service_name,
"aud": audience,
"iat": int(time.time()),
"exp": int(time.time()) + ttl_seconds
}
header_b64 = self._b64url_encode(json.dumps(header).encode())
payload_b64 = self._b64url_encode(json.dumps(payload).encode())
signing_input = f"{header_b64}.{payload_b64}".encode()
signature = hmac.new(self.secret, signing_input, hashlib.sha256).digest()
return f"{header_b64}.{payload_b64}.{self._b64url_encode(signature)}"
def verify_token(self, token, expected_audience):
try:
header_b64, payload_b64, signature_b64 = token.split('.')
signing_input = f"{header_b64}.{payload_b64}".encode()
expected_sig = hmac.new(self.secret, signing_input, hashlib.sha256).digest()
if not hmac.compare_digest(expected_sig, self._b64url_decode(signature_b64)):
return False
payload = json.loads(self._b64url_decode(payload_b64))
return (payload.get("aud") == expected_audience
and payload.get("exp", 0) > time.time())
except Exception:
return False
if __name__ == "__main__":
jwt = JWTMock("shared-secret-key")
auth_service = jwt.create_token("auth-service", "payment-service")
print("Token:", auth_service)
print("Verified by payment-service:", jwt.verify_token(auth_service, "payment-service"))
print("Rejected by wrong audience:", jwt.verify_token(auth_service, "other-service"))
Output
Token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhdXRoLXNlcnZpY2UiLCJzdWIiOiJhdXRoLXNlcnZpY2UiLCJhdWQiOiJwYXltZW50LXNlcnZpY2UiLCJpYXQiOjE3MjQ5OTM2MDAsImV4cCI6MTcyNDk5NzIwMH0.5m4kT-T3P1wP5f2KcQhB0LQF6V3uZZzFjBYA_MdZQOM
Verified by payment-service: True
Rejected by wrong audience: False
How it works
This implementation manually constructs JWTs using the standard library. The header and payload are JSON-encoded, base64url-encoded, and signed with HMAC-SHA256. Verification recomputes the signature and uses hmac.compare_digest to prevent timing attacks. Audience and expiration checks enforce that only the intended service can accept the token. Using only stdlib keeps the code dependency-free and ideal for prototypes or tests.
Common mistakes
- Forgetting to add padding when decoding base64url strings
- Using `==` instead of `hmac.compare_digest` for signature comparison
- Not checking the `exp` claim when verifying the token
Variations
- Use the PyJWT library for production code with more algorithms and validation features
- Add `nbf` (not before) or `jti` (token ID) claims for stronger security
Real-world use cases
- Authenticating internal microservices when calling each other's APIs
- Generating short-lived tokens for server-to-server webhook calls
- Mocking JWT in integration tests without standing up an identity provider
Sponsored
More from Microservices patterns
- BFF aggregation pattern: combine multiple service responses in Python easy
- Backward Compatible Schema Evolution in Python medium
- Bulkhead Thread Pool per Service Mock in Python medium
- CQRS with Separate Read and Write Repositories in Python medium
- Cache-Aside Pattern in Python: Per-Service Mock easy
- Consumer Driven Contract Pact Mock in Python medium
Keep learning
Related tutorials and quizzes for this topic.