Skip to main content

Detect tampered signed values

When you transmit data to a client that must be returned unchanged, such as a session ID or a password reset token, you need a way to verify that the client did not modify the value. If a user changes a single byte of a signed value, itsdangerous identifies the mismatch and prevents the tampered data from being processed.

The Signer class in itsdangerous.signer provides the core mechanism for this integrity check. It appends a cryptographic signature to your data using a secret key. When you attempt to retrieve the original value using unsign(), the library recalculates the signature and compares it to the one provided. If they do not match—indicating the data or the signature was altered—it raises a BadSignature exception.

The following example demonstrates how to initialize a Signer, protect a byte string, and handle the exception that occurs when the signed value is tampered with.

from itsdangerous import BadSignature, Signer

# Initialize the Signer with a fixed secret key.
signer = Signer(b"secret-key")
original_data = b"my-secure-data"

# Call sign exactly once to protect the data.
signed_value = signer.sign(original_data)

# Call unsign the first time to verify the valid signed value.
verified_data = signer.unsign(signed_value)
assert verified_data == original_data

# Simulate tampering by changing one byte of the signed value.
tampered_value = b"X" + signed_value[1:]

# Call unsign the second time inside a try block to catch the expected failure.
try:
signer.unsign(tampered_value)
except BadSignature as e:
# The exception contains the payload that failed the signature test.
assert e.payload == b"Xy-secure-data"

Internally, Signer.unsign splits the input string using the configured separator (defaulting to .). It then passes the payload and the signature to verify_signature(). This method iterates through the available secret keys—supporting key rotation if a list was provided to the constructor—and uses the SigningAlgorithm to check the HMAC. If no key produces a matching signature, unsign() raises BadSignature from itsdangerous.exc, ensuring that tampered data is never treated as valid.