Blog · Auth
How to add magic-link login to Django
The user types an email address. Django sends a one-time link. The user opens the link and the site starts a session. The project needs no reset flow and no social provider.
django-mail-auth
is one small dependency with three parts. mailauth holds the backend and the
/accounts/login/ views. mailauth.contrib.admin puts the Django admin behind
the same flow. mailauth.contrib.user adds an EmailUser model with no password
field.
uv add django-mail-auth
Decide the user model first
This decision goes into the first migration, and a later change is expensive. Choose one of three options. Install mailauth.contrib.user and set
AUTH_USER_MODEL = "mailauth_user.EmailUser". Write a custom user model with
email as the USERNAME_FIELD. Or keep the stock auth.User
model.
Two accounts with one email address can log in as each other. The
email field on stock auth.User has no unique=True constraint.
If two rows hold the same address, MailAuthBackend.authenticate() returns the first match
and raises no error. A second signup with another person's address then receives a valid link to that
account. To stay on stock auth.User, add a UniqueConstraint in a migration
and a validator on the admin form.
Settings
Edit INSTALLED_APPS in place. Do not append. Django resolves admin templates and the
admin login view in app order, so the app that overrides must load first. Put
mailauth.contrib.admin above django.contrib.admin. In the reverse order the
stock password login stays on /admin/, and Django gives no warning.
INSTALLED_APPS = [
# ... existing entries kept ...
"mailauth.contrib.admin", # must precede django.contrib.admin
"django.contrib.admin",
"mailauth",
]
AUTHENTICATION_BACKENDS = [
"mailauth.backends.MailAuthBackend",
"django.contrib.auth.backends.ModelBackend",
]
LOGIN_URL = "mailauth:login"
LOGIN_REDIRECT_URL = "/"
Then add path("accounts/", include("mailauth.urls")) to the root URL configuration. Give
it no namespace argument, because the package declares app_name itself.
Templates and email
The package ships the email body and the subject. Supply three HTML pages:
registration/login.html, registration/login_requested.html, and
registration/logged_out.html. The package also needs an email backend. Set
EMAIL_URL=consolemail:// and the link prints to the runserver output. Without
that setting Django uses SMTP on localhost:25, the login form accepts the address, and no
mail arrives.
Or give the task to an agent. It reads the same setup from a maintained reference file and applies it to the repository:
/django-seedkit add passwordless magic-link login
The reference holds the full setup, and the default_auto_field pin that keeps
makemigrations --check green:
auth.md
· What Django Seedkit is