Planet Python
Follow
Bob Belderbos: Unsubscribe links without a login: Django signing
Django's signing module allows secure unsubscribe links without user login or sessions. An insecure approach directly using user IDs in URLs is vulnerable to mass unsubscribing. Storing random tokens in the database is a common but more complex fix. Django's django.core.signing module provides tamper-evident tokens without requiring database storage by signing a value (like a user's primary key) with a SECRET_KEY.A "salt" is crucial to prevent token collisions between different features, ensuring a token for one purpose (e.g., announcements) cannot be used for another (e.g., forum notifications). While signed, tokens are not secret; the data within them is readable but cannot be altered without invalidating the signature. Therefore, do not sign sensitive information meant to be hidden. Crucially, unsubscribe actions should happen on a POST request, not a GET request, to prevent mail scanners and prefetchers from unintentionally unsubscribing users. A confirmation page on GET, followed by a POST to finalize the action, is the recommended flow.Unsubscribe tokens often do not require expiry, as clicking an old link twice yields the same safe outcome. However, for sensitive actions like magic login links, max_age argument in signing.loads provides expiry without database storage. For single-use token scenarios, like email verification, additional state management (database record of used tokens) is necessary since the signature alone cannot track usage.