Django Sesame
Django Sesame provides frictionless authentication for your Django project using "Magic Links". It generates URLs with embedded authentication tokens, allowing users to log in or access specific content without passwords or traditional sessions. The library supports various token-based authentication use cases and is actively maintained, with current version 3.2.3 compatible with recent Django and Python versions.
Common errors
-
django.contrib.auth.backends.ModelBackend.authenticate() received an unexpected keyword argument 'url_auth_token'
cause Using the deprecated `url_auth_token` argument with `authenticate()` after upgrading to `django-sesame` v2.0 or later.fixUpdate your code to use the `sesame` keyword argument: `user = authenticate(request, sesame=token_value)`. -
Magic link works once, then fails subsequent attempts, even if 'SESAME_ONE_TIME' is False.
cause If `SESAME_ONE_TIME` is enabled (even implicitly if not explicitly `False`) and the user's `last_login` field is updated by another login mechanism or `authenticate(update_last_login=True)`, the token becomes invalid.fixEnsure `SESAME_ONE_TIME = False` explicitly in settings if tokens should be reusable. If you need reusable tokens and also update `last_login` through other means, consider setting `SESAME_INVALIDATE_ON_PASSWORD_CHANGE = False` (with security review) or regenerate tokens.
Warnings
- breaking Changing most Django Sesame settings (e.g., `SECRET_KEY`, `SESAME_TOKEN_NAME`, `SESAME_TOKENS`) will invalidate all previously generated authentication tokens.
- breaking Upgrading Django versions can invalidate existing magic links/tokens, particularly long-lived ones. This is because Django's password hashers increase their work factor with new releases, making a password hash upgrade indistinguishable from a password change to `django-sesame`.
- gotcha One-time tokens (`SESAME_ONE_TIME = True`) can fail if sent via email, as email providers often fetch links for previews or security scans, consuming the token before the actual user clicks it.
- gotcha Safari's 'Protection Against First Party Bounce Trackers' can cause issues (clearing cookies, logging out users) when `django-sesame` redirects after successful authentication.
- gotcha The primary keys of users are stored in clear text within tokens. While this is not inherently a security flaw if the token is secure, it's a privacy consideration.
Install
-
pip install django-sesame -
pip install django-sesame[ua]
Imports
- get_query_string
from sesame.utils import get_query_string
- get_user
from sesame.utils import get_user
- LoginView
from sesame.views import LoginView
- ModelBackend
from sesame.backends import ModelBackend
- authenticate (decorator)
from sesame.decorators import authenticate
- authenticate (function)
user = authenticate(url_auth_token=token_value)
from django.contrib.auth import authenticate user = authenticate(request, sesame=token_value)
Quickstart
import os
from django.contrib.auth import get_user_model
from django.urls import path
from sesame.views import LoginView
from sesame.utils import get_query_string
# --- Django settings.py (example additions) ---
# AUTHENTICATION_BACKENDS = [
# 'django.contrib.auth.backends.ModelBackend',
# 'sesame.backends.ModelBackend',
# ]
# # Optional: Configure token lifetime (e.g., 10 minutes for login by email)
# import datetime
# SESAME_MAX_AGE = datetime.timedelta(minutes=10)
# --- Your app's urls.py (example) ---
urlpatterns = [
path("sesame/login/", LoginView.as_view(), name="sesame-login"),
]
# --- Example usage in a view or script ---
User = get_user_model()
# Create or get a user (e.g., for 'jane.doe@example.com')
try:
user = User.objects.get(email="jane.doe@example.com")
except User.DoesNotExist:
user = User.objects.create_user("jane.doe", "jane.doe@example.com", "password123")
user.set_unusable_password() # If only using magic links, make password unusable
user.save()
# Assuming a base URL like 'http://127.0.0.1:8000'
base_url = os.environ.get('DJANGO_BASE_URL', 'http://127.0.0.1:8000')
login_path = '/sesame/login/'
# Generate a magic link
magic_link = base_url + login_path + get_query_string(user)
print(f"Magic link for {user.email}: {magic_link}")
# To test, manually visit this link in a browser while logged out.