DEV Community

Rupesh Mishra
Rupesh Mishra

Posted on

Implementing Email and Mobile OTP Verification in Django: A Comprehensive Guide

In today's digital landscape, ensuring the authenticity of user accounts is paramount for web applications. One effective method to achieve this is through email and mobile number verification using One-Time Passwords (OTPs). This article will guide you through the process of implementing OTP verification in a Django project, explaining its importance and providing actionable steps for implementation.

Table of Contents

  1. Introduction
  2. Why OTP Verification Matters
  3. Prerequisites
  4. Step-by-Step Implementation
  5. Best Practices and Considerations
  6. Conclusion

Introduction

One-Time Passwords (OTPs) are unique, temporary codes used to verify a user's identity. By implementing OTP verification for both email and mobile numbers, you add an extra layer of security to your application, ensuring that users have access to the contact methods they've provided.

Why OTP Verification Matters

  1. Enhanced Security: OTP verification significantly reduces the risk of unauthorized access and account takeovers.
  2. User Authentication: It confirms that users have provided valid contact information, which is crucial for account recovery and communication.
  3. Fraud Prevention: It helps prevent the creation of fake accounts, as users must prove ownership of their email and phone number.
  4. Compliance: Many regulatory standards require multi-factor authentication, which OTP verification can help satisfy.
  5. User Trust: Implementing strong security measures like OTP verification builds user confidence in your application.

Prerequisites

Before we begin, make sure you have the following:

  • Python 3.x installed
  • Basic knowledge of Django
  • A Django project set up (if not, we'll cover that in the steps)

Step-by-Step Implementation

Let's dive into the process of implementing OTP verification in a Django project.

Step 1: Set up the Django project and app

First, let's create a new Django project and app:

django-admin startproject otp_verification
cd otp_verification
python manage.py startapp user_auth
Enter fullscreen mode Exit fullscreen mode

Add 'user_auth' to INSTALLED_APPS in your project's settings.py file:

INSTALLED_APPS = [
    ...
    'user_auth',
]
Enter fullscreen mode Exit fullscreen mode

Step 2: Install required packages

We'll need a couple of additional packages:

pip install django-otp pyotp
Enter fullscreen mode Exit fullscreen mode

Step 3: Create the User model

In your user_auth/models.py file, create a custom user model:

from django.contrib.auth.models import AbstractUser
from django.db import models

class CustomUser(AbstractUser):
    email = models.EmailField(unique=True)
    mobile_number = models.CharField(max_length=15, unique=True)
    is_email_verified = models.BooleanField(default=False)
    is_mobile_verified = models.BooleanField(default=False)
    email_otp = models.CharField(max_length=6, null=True, blank=True)
    mobile_otp = models.CharField(max_length=6, null=True, blank=True)
Enter fullscreen mode Exit fullscreen mode

Step 4: Create OTP generation and verification functions

Create a new file user_auth/utils.py:

import pyotp
from datetime import datetime, timedelta

def generate_otp():
    totp = pyotp.TOTP(pyotp.random_base32(), interval=300)  # 5 minutes validity
    return totp.now()

def verify_otp(otp, user_otp):
    return otp == user_otp
Enter fullscreen mode Exit fullscreen mode

Step 5: Create views for registration and OTP verification

In your user_auth/views.py file:

from django.shortcuts import render, redirect
from django.contrib.auth import login
from .models import CustomUser
from .utils import generate_otp, verify_otp
from django.core.mail import send_mail
from django.conf import settings

def register(request):
    if request.method == 'POST':
        username = request.POST['username']
        email = request.POST['email']
        mobile_number = request.POST['mobile_number']
        password = request.POST['password']

        user = CustomUser.objects.create_user(username=username, email=email, 
                                              mobile_number=mobile_number, password=password)

        # Generate and save OTPs
        email_otp = generate_otp()
        mobile_otp = generate_otp()
        user.email_otp = email_otp
        user.mobile_otp = mobile_otp
        user.save()

        # Send email OTP
        send_mail(
            'Email Verification OTP',
            f'Your OTP for email verification is: {email_otp}',
            settings.EMAIL_HOST_USER,
            [email],
            fail_silently=False,
        )

        # Send mobile OTP (you'll need to integrate with an SMS service)
        # For this example, we'll just print it
        print(f"Mobile OTP: {mobile_otp}")

        return redirect('verify_otp', user_id=user.id)

    return render(request, 'register.html')

def verify_otp(request, user_id):
    user = CustomUser.objects.get(id=user_id)

    if request.method == 'POST':
        email_otp = request.POST['email_otp']
        mobile_otp = request.POST['mobile_otp']

        if verify_otp(email_otp, user.email_otp) and verify_otp(mobile_otp, user.mobile_otp):
            user.is_email_verified = True
            user.is_mobile_verified = True
            user.email_otp = None
            user.mobile_otp = None
            user.save()
            login(request, user)
            return redirect('home')
        else:
            return render(request, 'verify_otp.html', {'error': 'Invalid OTP'})

    return render(request, 'verify_otp.html')
Enter fullscreen mode Exit fullscreen mode

Step 6: Create URL patterns

In your user_auth/urls.py file:

from django.urls import path
from . import views

urlpatterns = [
    path('register/', views.register, name='register'),
    path('verify_otp/<int:user_id>/', views.verify_otp, name='verify_otp'),
]
Enter fullscreen mode Exit fullscreen mode

Don't forget to include these URLs in your project's main urls.py file.

Step 7: Create templates

Create two HTML templates in your templates directory:

register.html:

<form method="post">
    {% csrf_token %}
    <input type="text" name="username" placeholder="Username" required>
    <input type="email" name="email" placeholder="Email" required>
    <input type="text" name="mobile_number" placeholder="Mobile Number" required>
    <input type="password" name="password" placeholder="Password" required>
    <button type="submit">Register</button>
</form>
Enter fullscreen mode Exit fullscreen mode

verify_otp.html:

<form method="post">
    {% csrf_token %}
    <input type="text" name="email_otp" placeholder="Email OTP" required>
    <input type="text" name="mobile_otp" placeholder="Mobile OTP" required>
    <button type="submit">Verify OTP</button>
</form>
Enter fullscreen mode Exit fullscreen mode

Step 8: Configure email settings

In your project's settings.py file, add the following email configuration:

EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com'  # Use your email provider's SMTP server
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = 'your_email@gmail.com'
EMAIL_HOST_PASSWORD = 'your_email_password'
Enter fullscreen mode Exit fullscreen mode

Replace the placeholder values with your actual email credentials.

Step 9: Run migrations

Apply the database migrations:

python manage.py makemigrations
python manage.py migrate
Enter fullscreen mode Exit fullscreen mode

Step 10: Run the server

Start the Django development server:

python manage.py runserver
Enter fullscreen mode Exit fullscreen mode

Best Practices and Considerations

  1. Security: In a production environment, use more secure methods for storing OTPs, such as hashing them before saving to the database.
  2. SMS Integration: Integrate with a reliable SMS service provider to send mobile OTPs.
  3. OTP Expiry: Implement a mechanism to expire OTPs after a certain time period.
  4. Rate Limiting: Implement rate limiting to prevent abuse of the OTP generation and verification endpoints.
  5. Error Handling: Add robust error handling and user feedback for a smoother user experience.
  6. Resend OTP: Provide an option for users to request a new OTP if they don't receive the first one.
  7. Progressive Enhancement: Allow users to access limited functionality even if they haven't verified their contact methods, but require verification for sensitive actions.

Conclusion

Implementing email and mobile OTP verification in your Django application significantly enhances security and user trust. By following this guide, you've learned how to set up a basic OTP verification system. Remember to adapt this implementation to your specific needs and always prioritize user data security.

As you continue to develop your application, consider integrating additional security measures and regularly updating your authentication methods to stay ahead of potential threats. With OTP verification in place, you're taking a crucial step towards building a more secure and trustworthy web application.

Connect with me on my social media platforms for more updates and insights:

Top comments (0)