How to Implement a CSRF Token Double Submit Mock in Python

A mock CSRF protection class that generates and validates double-submit tokens using HMAC-SHA256 with a secret key.

Medium Python 3.9+ Aug 9, 2026 Auth & security at scale 13 views 0 copies

Python code

33 lines
Python 3.9+
import hmac
import hashlib
import secrets


class CSRFProtection:
    def __init__(self, secret_key: str):
        self.secret_key = secret_key.encode("utf-8")

    def generate_token(self) -> str:
        random_value = secrets.token_hex(16)
        signature = hmac.new(
            self.secret_key, random_value.encode("utf-8"), hashlib.sha256
        ).hexdigest()
        return f"{random_value}.{signature}"

    def validate_token(self, token: str, submitted_token: str) -> bool:
        if token != submitted_token:
            return False
        random_value, signature = token.split(".")
        expected_signature = hmac.new(
            self.secret_key, random_value.encode("utf-8"), hashlib.sha256
        ).hexdigest()
        return hmac.compare_digest(signature, expected_signature)


if __name__ == "__main__":
    csrf = CSRFProtection("my-super-secret-key")
    stored_token = csrf.generate_token()
    print(f"Stored token: {stored_token}")
    print(f"Valid submission: {csrf.validate_token(stored_token, stored_token)}")
    fake_token = csrf.generate_token()
    print(f"Tampered submission: {csrf.validate_token(stored_token, fake_token)}")

Output

stdout
Stored token: 2f5a8b7c4d9e1f3a6b8c0d2e4f6a8b0c.a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2
Valid submission: True
Tampered submission: False

How it works

The generate_token method creates a random hex value and signs it with HMAC-SHA256 using a secret key. The token format is random_value.signature. During validation, the submitted token must exactly match the stored token, and then the signature is recomputed and compared using hmac.compare_digest to prevent timing attacks. This double-submit approach ensures that only someone with the secret key can forge or modify tokens. The secrets module is used for cryptographically secure random generation.

Common mistakes

  • Comparing signatures with `==` instead of `hmac.compare_digest`
  • Storing the secret key in plaintext in source code
  • Not checking that the token format is correct before splitting
  • Using a weak random generator like `random` for token generation

Variations

  1. Use a cookie-based double-submit where the same token is set in a cookie and a hidden form field
  2. Use signed tokens with a timestamp to enforce expiration

Real-world use cases

  • Protecting web forms in a Flask or Django app from cross-site request forgery attacks.
  • Securing AJAX POST endpoints where a CSRF token is sent in both a header and a form field.
  • Implementing double-submit token validation in a microservice gateway to guard state-changing APIs.

Sponsored

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from Auth & security at scale

Related tutorials and quizzes for this topic.