How to Mock a CORS Allow Origin Whitelist in Python
A decorator-based mock of a CORS middleware that whitelists allowed origins and injects proper Access-Control-Allow-Origin headers while rejecting others.
Python code
42 linesfrom functools import wraps
class MockCORSConfig:
def __init__(self, allowed_origins):
self.allowed_origins = allowed_origins
def is_origin_allowed(self, origin):
return origin in self.allowed_origins
def cors_middleware(config):
def decorator(handler):
@wraps(handler)
def wrapper(origin=None, *args, **kwargs):
if origin is None or not config.is_origin_allowed(origin):
return {
"status": 403,
"body": "Forbidden: Origin not in whitelist",
"headers": {},
}
response = handler(*args, **kwargs)
response["headers"]["Access-Control-Allow-Origin"] = origin
response["headers"]["Access-Control-Allow-Methods"] = "GET, POST, PUT, DELETE"
response["headers"]["Access-Control-Allow-Headers"] = "Content-Type, Authorization"
return response
return wrapper
return decorator
@cors_middleware(MockCORSConfig({"https://trusted-site.com", "https://api.partner.net"}))
def get_user_data(user_id):
return {"status": 200, "body": {"user_id": user_id, "name": "Alice"}, "headers": {}}
if __name__ == "__main__":
result_allowed = get_user_data(origin="https://trusted-site.com", user_id=123)
print("Allowed origin ->", result_allowed)
result_blocked = get_user_data(origin="https://evil-site.com", user_id=999)
print("Blocked origin ->", result_blocked)
Output
Allowed origin -> {'status': 200, 'body': {'user_id': 123, 'name': 'Alice'}, 'headers': {'Access-Control-Allow-Origin': 'https://trusted-site.com', 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE', 'Access-Control-Allow-Headers': 'Content-Type, Authorization'}}
Blocked origin -> {'status': 403, 'body': 'Forbidden: Origin not in whitelist', 'headers': {}}
How it works
The MockCORSConfig class holds a set of allowed origins and exposes is_origin_allowed to check membership. The cors_middleware decorator wraps a handler and intercepts an origin parameter; if it's missing or not in the whitelist, it returns a 403 response immediately. When the origin passes, it calls the original handler and enriches its response headers with the CORS headers, reflecting the exact origin. The @wraps decorator preserves the handler's metadata (name, docstring) so the wrapped function behaves like the original.
Common mistakes
- Forgetting to pass the origin parameter or defaulting it to None, which silently blocks all requests
- Hardcoding headers in the handler instead of injecting them via middleware, causing inconsistency
- Not using `@wraps`, which breaks introspection and debugging tools relying on function metadata
Variations
- Use a regex or URL-prefix pattern instead of an exact set to support subdomain wildcards like '*.trusted-site.com'
- Cache the allowed-origin lookup in an LRU cache if the whitelist is large and checked frequently
Real-world use cases
- Unit testing a web API handler to verify CORS headers are applied correctly for trusted frontend domains.
- Simulating CORS enforcement in a local development environment before deploying to a real API gateway.
- Validating that preflight OPTIONS requests from unknown origins are rejected during security audits.
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.