Django and email verification

by mark | 26 Feb 2022, 9:02 p.m.

I had a fun (or, more correctly, "fun") time getting email verification set up on this website. Django's default auth mechanism will create an active account on demand but I want to add web features that let users send mail to themselves. So to avoid someone scripting ten million spams through this website I need to ensure users' emails are genuine. 

Basically I wanted a two step registration flow: create an account, and then click on a link to prove the email is actually yours. 

There are django apps that already do this but I wanted to roll my own. Also having based this site off the standard auth package it is not just a case of "download this new app" as there are already links between auth and everything else. Transplanting another app in is more pain than figuring out how to jam in two step registration to the current auth flow. 

First step is to amend the current flow so that all new accounts are created in an unusable state. This was quite straightforward in the end as I already had a custom user model with a very lightweight sign up view. You go to http://www.rkdouglas.co.uk/accounts/signup/ and this view renders a template with a form in it. You fill in the form and press the button and a user account is created. What happened here was I hijacked the form_valid method; this is the thing that saves the new user. I set the user's is_active property to False and save it. This is from the standard auth models; actually removing users from the database can cause problems so "deleting" means "mark inactive". So the new user is created but the standard active checks will mean they cannot do anything like log in. They are then redirected to a template that says "yo check your mail son"

Second step was to actually send the mail. This was the pain. Well not sending an email that is easy. It is creating the one time link that is the pig. 

I needed a destination first of all. I made a user activation view that was subclassed from template view. This looked for two URL parameters, the UID being activated and the activation token. For now the view just spat out the two URL params. 

Now I needed to fabricate the link to send. Again standard auth helps. It already does this for password reset requests using a token generator. So I borrowed this using a different hash. This can be stuffed into the URL. 

Email is then template driven. 

Final thing was to build the logic that tests whether the token is right. The token generator also validates tokens which is neat. If it is valid then you mark the account as active. Now the log in works. Hooray!

No comments

Back to all articles