How to Set up a User Login That Requires Text Message Authentication in Django



Python


In this article, we show how to set up a user login that requires text message authentication in Django.

So what this means is, how can we log in a user but add the extra security feature of the user having to enter a verification code being sent to his/her phone?

Many websites implement text message verification, because it's an added security feature to protect an account.

Bank websites generally implement this when a user is logging in or a user is sending money out.

A text message with normally a 6- or 7-digit number is sent to a user's phone. The user must then enter in this verification code. Only when a user enters the correct verification code will the process continue (either the user is logged in or the transaction is completed).

So we will show how to implement this verification system in Django.

So, before we get into the code, we will make it known now that we will use the twilio SMS gateway in order to send text messages. In order to send text messages, you need to use an SMS gateway to send the text messages. Twilio is one of the most popular SMS gateway services. In order to use Twilio, you will need to create an account. When you create an account, you need 3 pieces of information to send text messages: the twilio SID number, the twilio auth token, and the twilio-generated phone number that will send the text message.

To install twilio on Django, use the following line shown below.



This takes a few seconds to install twilio.

After this is done, then you need to add 'django-twilio' to the INSTALLED_APPS list in the settings.py file.

This is shown below.



Since you've now added, 'django-twilio', to the INSTALLED_APPS list in the settings.py file, then you must apply migrations.

This is done with the following line below.



Now the django-twilio app is installed sitewide across the project.

This completes the installation.

Now that everything is installed, we need to add a few lines of code into the settings.py file.

We need to add the twilio account SID, the twilio auth token, and the twilio phone number that twilio gave us that we will send messages from.

So it will look like what is shown below.



So since these are constants (unless of course you change your twilio account or get a new phone number to use), you want to keep these in the settings.py file.

So this completes the installation and full setup of twilio for Django.

Now we go into our actual Python code.

forms.py File

So the first page we need to create is the standard login page.

This form will have the username and password fields.

We create a Django form which is shown below.



So in this forms.py, we create a form named Loginform.

This form has 2 fields, username and password.

This is just like a regular login form.

models.py File

Another thing we need to do is create a model that stores a random-generated text code.

We will generate a random 6-digit text code.

The idea is that we will then send this 6-digit text code to the user's phone via SMS.

If the code that the user enters matches the code in teh database, we then log the user in (or send the money or process the transaction).

This model is shown below.



So let's go into the heart of this code.

So the model is named UserTextMessage.

The first field is user. This is the user that we are going to text message.

The second field is code. This is the code that we want to store in the database and the code we want to send the user. We generate a random 6-digit code with a pre_save signal in Django and store it in this field.

The third field is date. This is the date that the text message was added. We want to include this because we're going to make it so that the code sent via SMS to the user is only going to be valid for 1 minute. After 1 minute, it is no longer valid. This is how most websites work.

utils.py file

Because the model above uses a function to generate a random text code that is in the utils.py file, we will now show the code in the utils.py file.

This is shown in the code below.



In order to use the random function in Python, we must import random.

We then create a function, random_text_msg_digit_code_generator(), which generates a random 6-digit code. This function then returns this variable, result.

We then create a function, unique_text_msg_code_generator() and pass in the variable, instance

The point of this function is check to make sure that the text code that is in the database isn't repeated if the user requests another text code. It makes it so that the next text message will absolutely be different than the previous one.

So next we will look at the views.py file for the original login page.

views.py file for the Login page

So in this views.py file, we take the input that the user has entered into the form, which is their login username and password and we authenticate the user. We then generate a text code for the user and send the text code. We then redirect the user to the page that contains the page where a user can enter the text code.

Below is the contents of this function in the views.py file.



So the first thing we do is import everything that we need such as the login form and the UserTextMessage model we created. Since we are sending a text code with the Twilio SMS gateway service, we must import Client from twilio.rest

We now create our function in the views.py file. We call this function, logintextcode()

We create two variables, uservalue and passwordvalue, to hold the values from the login form that the user entered in.

We then create a variable, form, which is equal to the form we created in the forms.py file for a user log in.

If the form is valid, we get the data from the form fields.

We then authenticate the user. If the user is authenticated, the user variable will hold the value of the user. If the user is not authenticated, the value of user will be None.

If the user is authenticated, then we create a session variable named 'login' that we set equal to uservalue. We also create a session variable named 'password' that we set equal to passwordvalue. The reason we create session variables is because in the next view (where the user enters the text code), we need access to the login and password values, so that we can log in the user if the right text code is entered.

We then create a variable, currentuser, which we set equal to, currentuser= User.objects.get(username=uservalue)

The reason we need the current user is because we need to create a text code for the current user, which is what we do in the next line.

In the next line, we create a text code for the user using the line, UserTextMessage.objects.update_or_create(user= currentuser)

This line will update or create the text code in the UserTextMessage model for the given current user.

We then retrieve the code from the UserTextMessage model for the given user that was just generated.

We then enter the phone number of the user. You may need to adjust this line to get the phone number of the current user from the database. It wouldn't just be entered directly like this.

Then to send out the text message, we use the first must authenticate into our Twilio account.

We then create a message through the client.messages.create() function. Inside of this function, we specify our message in the body attribute, the phone number we are sending the text message to, and the phone number we are sending the text message from. Since we are sending out a code with this message, we add the variable, codetoenter, into the body of the text.

We have to pass in the login form into our context dictionary for it to be rendered on the page. We then reidrect the user to the page where the user has to enter his/her text code in order to get logged into his/her account.

Text Code Page

So the next thing we have to do is create the form for the text code entry.

This is a very simple form, which only contains one text input.

This is shown below.



So, as you can see, this is a simple form that has one text input that accepts an integer.

Now we just need the views.py function to process this text input.

This is shown below.



We then create a function in the views.py file, textcodepage()

Using the session variables we created in our past view, we set the login session variable and the password session variable to the variables, currentusername and currentpassword.

The line above gets the current user.

We then want to know how much time has passed since the text message was sent. We give the user a 45-second period to confirm the text. We do this because we do not want this is time-sensitive. This is standard on most websites.

So we get the current time- specified by, timezone.now()

We then get the time that the text message was sent.

We then create a variable, diff, which represents the difference between the current time and the time in which the text message was sent.

We then create a variable, form, and set it equal to, Textmsgcodeform(request.POST or None)

This gets the form we created in the forms.py file.

If the form is valid and the the time that has elapsed since the text message was sent is less than 45 seconds, we get the text message entered in and store it in the variable, textmsgcode.

We then get the currentuser by the line, currentuser= User.objects.get(username= currentusername)

We get the code that was generated for the user in the UserTextMessage model in the code field.

If the code entered in is the same as the code in the database table, then this completes verification. We authenticate the user with the Django authenticate() function and then log the user in with the Django login() function.

If the code is not the same, we render an error.

If the time has expired, we render an error.

For this page, you'll also want to have a resend SMS link, so that a text message can be sent either if the time has expired or the user failed to receive a text message. We'll show how to do this in another tutorial.

But this is all that is needed to set up a login that requires text message authentication in Django.


Related Resources

How to Randomly Select From or Shuffle a List in Python



HTML Comment Box is loading comments...