How to build an OTP verification system using Python?

Even if your password is stolen, the OTP verification system acts as a key element of security. It eliminates the need to remember passwords, acts as an extra layer of security, and reduces the risk of phishing.

You might as well learn to use Python to build an OTP verification system. It will send an OTP to your mobile phone number, which is valid for only two minutes. If you enter the wrong OTP three times in a row, your account will be locked.

1. Install Tkinter, Twilio and Random modules

Tkinter allows you to create desktop applications. It provides various widgets such as buttons, labels, and text boxes to make developing applications easier.

Twilio modules help you integrate communication capabilities and authentication like SMS, MMS, and phone calls right into your application. It has a cloud-based infrastructure along with amazing features like number configuration, message templates, and call recording.

To install the Twilio module and Tkinter module, execute the following commands in the terminal:

pip install twilio tk

The Random module is a built-in Python module for generating pseudo-random numbers. With this module you can generate random numbers, select random elements from lists, shuffle list contents, and more. You can use it to build a dice rolling simulation, a list shuffler, or a random password generator.

2. Generate Twilio API and get phone number

To use Twilio and send OTP requests to your phone, you need authentication credentials as well as a Twilio phone number. to this end:

1. Register a Twilio account and access the Twilio console.

2. Scroll down and click the “Get Phone Number” button. Copy the generated phone number.

3. Scroll down to the “Account Information” section. Copy the “Account SID” and “Authentication Token”.

3. Building the structure of the application

As a disclaimer, you can find the complete source code for building an OTP verification system using Python in this GitHub repository.

Import the necessary modules and set authentication credentials. Initializes the Twilio client software to authenticate and serve as the entry point for API calls. Set the expiry time to two minutes.

Define a class: OTPVerification, and initialize the constructor to set the default value of the variable, initialize the root window, and set the title and dimensions of the application.

import tkinter as tk
from tkinter import messagebox
from twilio.rest import Client
import random
import threading
import time

account_sid = "YOUR_ACCOUNT_SID"
auth_token = "YOUR_AUTH_TOKEN"
client = Client(account_sid, auth_token)
expiration_time = 120

class OTPVerification:
 def __init__(self, master):
 self.master = master
 self.master.title('OTP Verification')
 self.master.geometry("600x275")
 self.otp = None
 self.timer_thread = None
 self.resend_timer = None
 self.wrong_attempts = 0
 self.locked = False
 self.stop_timer = False

Define three tags to request the mobile number and OTP, and display a timer after the program sends the OTP. Set the parent element, the text it should display, and the font style it should have. Likewise, create two input widgets to get user input. Set the parent element, width and font style.

Create three buttons to send OTP, resend OTP and verify OTP. Set the parent element, the text it should display, the command it will execute when clicked, and its font style. Use the pack method to organize these elements.

self.label1 = tk.Label(self.master,
 text='Enter your mobile number:',
 fnotallow=('Arial', 14))
 self.label1.pack()

 self.mobile_number_entry = tk.Entry(self.master,
 width=20,
 fnotallow=('Arial', 14))
 self.mobile_number_entry.pack()

 self.send_otp_button = tk.Button(self.master,
 text='Send OTP',
 command=self.send_otp,
 fnotallow=('Arial', 14))
 self.send_otp_button.pack()

 self.timer_label = tk.Label(self.master,
 text='',
 fnotallow=('Arial', 12, 'bold'))
 self.timer_label.pack()

 self.resend_otp_button = tk.Button(self.master,
 text='Resend OTP',
 state=tk.DISABLED,
 command=self.resend_otp,
 fnotallow=('Arial', 14))
 self.resend_otp_button.pack()

 self.label2 = tk.Label(self.master,
 text='Enter OTP sent to your mobile:',
 fnotallow=('Arial', 14))
 self.label2.pack()

 self.otp_entry = tk.Entry(self.master,
 width=20,
 fnotallow=('Arial', 14))
 self.otp_entry.pack()

 self.verify_otp_button = tk.Button(self.master,
 text='Verify OTP',
 command=self.verify_otp,
 fnotallow=('Arial', 14))
 self.verify_otp_button.pack()

4. Build application functionality

Define a method start_timer() that runs timer_countdown in a separate thread.

def start_timer(self):
 self.timer_thread = threading.Thread(target=self.timer_countdown)
 self.timer_thread.start()

Define a method timer_countdown(). Record the start time and run an infinite loop that gets the current time and calculates the elapsed time and remaining time. If stop_timer is true, terminate the loop. If the remaining time is less than or equal to 0, an error message box is displayed indicating that the OTP has expired.

Activate the Resend OTP button, set OTP to none, and terminate. Otherwise, calculate the remaining minutes and seconds, display them on the timer label, and sleep for one second.

def timer_countdown(self):
 start_time = time.time()
 while True:
 current_time = time.time()
 elapsed_time = current_time - start_time
 remaining_time = expiration_time - elapsed_time
 if self.stop_timer:
 break
 if remaining_time <= 0:
 messagebox.showerror('Error', 'OTP has expired.')
 self.resend_otp_button.config(state=tk.NORMAL)
 self.otp = None
 break
 minutes = int(remaining_time // 60)
 seconds = int(remaining_time % 60)
 timer_label = f'Time Remaining: {minutes:02d}:{seconds:02d}'
 self.timer_label.config(text=timer_label)
 time.sleep(1)

Define a method send_otp(). If locked is true, the corresponding message is displayed. Otherwise the phone number is extracted and verified, generating a random OTP. Provide the mobile number obtained previously and use the client software to send the OTP to your phone number. Shows a message box, starts a timer, disables buttons, and clears input entirely.

def send_otp(self):
   if self.locked:
 messagebox.showinfo('Account Locked', 'Your account is locked. Try again later.')
 return
 mobile_number = self.mobile_number_entry.get()
 if not mobile_number:
 messagebox.showerror('Error', 'Please enter your mobile number.')
 return

 self.otp = random.randint(1000, 9999)
 message = client.messages.create(
 body=f'Your OTP is {self.otp}.',
 from_='TWILIO_MOBILE_NUMBER',
 to=mobile_number
 )
 messagebox.showinfo('OTP Sent', f'OTP has been sent to {mobile_number}.')
 self.start_timer()
 self.send_otp_button.config(state=tk.DISABLED)
 self.resend_otp_button.config(state=tk.DISABLED)
 self.otp_entry.delete(0, tk.END)
def send_otp(self):
   if self.locked:
 messagebox.showinfo('Account Locked', 'Your account is locked. Try again later.')
 return
 mobile_number = self.mobile_number_entry.get()
 if not mobile_number:
 messagebox.showerror('Error', 'Please enter your mobile number.')
 return

 self.otp = random.randint(1000, 9999)
 message = client.messages.create(
 body=f'Your OTP is {self.otp}.',
 from_='TWILIO_MOBILE_NUMBER',
 to=mobile_number
 )
 messagebox.showinfo('OTP Sent', f'OTP has been sent to {mobile_number}.')
 self.start_timer()
 self.send_otp_button.config(state=tk.DISABLED)
 self.resend_otp_button.config(state=tk.DISABLED)
 self.otp_entry.delete(0, tk.END)

Define a method resend_otp(). If locked, an appropriate message is displayed. Otherwise get and verify the phone number, regenerate a random OTP, resend the OTP, show the message box, start the timer, and disable the resend OTP button.

def resend_otp(self):
 if self.locked:
 messagebox.showinfo('Account Locked', 'Your account is locked. Try
again later.')
 return
 mobile_number = self.mobile_number_entry.get()
 if not mobile_number:
 messagebox.showerror('Error', 'Please enter your mobile number.')
 return

 self.otp = random.randint(1000, 9999)
 message = client.messages.create(
 body=f'Your OTP is {self.otp}.',
 from_='TWILIO_MOBILE_NUMBER',
 to=mobile_number
 )
 messagebox.showinfo('OTP Sent', f'New OTP has been sent to {mobile_number}.')
 self.start_timer()
 self.resend_otp_button.config(state=tk.DISABLED)

Define a method verify_otp(). Get the OTP and check if the user didn’t enter anything. If the stored OTP is None, the user is required to generate the OTP first. If the OTP entered by the user matches the stored OTP, OTP verification success is displayed, the timer is stopped, and the program exits. Otherwise check for bad input attempts. If you enter the wrong number more than 3 times, your account will be locked.

def verify_otp(self):
 user_otp = self.otp_entry.get()
 if not user_otp:
 messagebox.showerror('Error', 'Please enter OTP.')
 return
 if self.otp is None:
 messagebox.showerror('Error', 'Please generate OTP first.')
 return
 if int(user_otp) == self.otp:
 messagebox.showinfo('Success', 'OTP verified successfully.')
 self.stop_timer = True
 exit()
 else:
 self.wrong_attempts + = 1
 if self.wrong_attempts == 3:
 self.lock_account()
 else:
 messagebox.showerror('Error', 'OTP does not match.')

Define a method lock_account(). Set the lock status to true and display the label as “Account is locked”. Disable all labels, entries, and buttons. Stop the existing timer and start a new timer (10 minutes).

def lock_account(self):
 self.locked = True
 self.label1.config(text='Account Locked')
 self.mobile_number_entry.config(state=tk.DISABLED)
 self.send_otp_button.config(state=tk.DISABLED)
 self.timer_label.config(text='')
 self.resend_otp_button.config(state=tk.DISABLED)
 self.label2.config(text='')
 self.otp_entry.config(state=tk.DISABLED)
 self.verify_otp_button.config(state=tk.DISABLED)
 self.stop_timer = True
 countdown_time = 10 * 60
 self.start_countdown(countdown_time)

Define a method start_countdown(). If the remaining time is less than or equal to 0, reset the account. Otherwise, it will be displayed that the program has locked the account, and the callback will be used to try again within the remaining time.

def start_countdown(self, remaining_time):
 if remaining_time <= 0:
 self.reset_account()
 return

 minutes = int(remaining_time // 60)
 seconds = int(remaining_time % 60)
 timer_label = f'Account Locked. Try again in:
{minutes:02d}:{seconds:02d}'
 self.timer_label.config(text=timer_label)
 self.master.after(1000, self.start_countdown, remaining_time - 1)

Define a function reset_account(). Reset the state of all widgets and variables as before.

def reset_account(self):
 self.locked = False
 self.wrong_attempts = 0
 self.label1.config(text='Enter your mobile number:')
 self.mobile_number_entry.config(state=tk.NORMAL)
 self.send_otp_button.config(state=tk.NORMAL)
 self.timer_label.config(text='')
 self.resend_otp_button.config(state=tk.DISABLED)
 self.label2.config(text='Enter OTP sent to your mobile:')
 self.otp_entry.config(state=tk.NORMAL)
 self.verify_otp_button.config(state=tk.NORMAL)
 self.stop_timer = False

Create an instance of the root window and class, and run the Tkinter application.

if __name__ == '__main__':
 root = tk.Tk()
 otp_verification = OTPVerification(root)
 root.mainloop()

5. Output example using OTP verification

While running the OTP verification process, you will see a window asking for your mobile number. Enter your mobile phone number and country code, and then click the “Send OTP” button. You will receive a message that the program successfully sent the OTP and the button will be deactivated for two minutes. Check if the OTP has been received on the phone and enter it before it expires.

After entering the correct OTP before the timer expires, you will receive a message stating that the program has successfully verified the OTP, exit the program. If you do not enter it in time, you will receive a message box stating that the OTP has expired. You can click the “Resend OTP” button to generate a new OTP and send it to your mobile phone.

If you enter the wrong OTP, the program will display a message box stating “OTP does not match”.

If the OTP is entered incorrectly three times, all fields will be disabled and the account will be locked for ten minutes.

6. Use Twilio with Python

Using Twilio, you can build an SMS notification system for various events. You can use it with IoT devices to send text messages when the device’s value goes above or below a certain threshold or when an intruder is detected. You can also build a secure login system with two-factor authentication, build a WhatsApp chatbot and an appointment reminder system.

Apart from this, you can also use it for phone number verification, marketing campaigns, sending surveys and collecting feedback. When building any application, always keep an eye on Twilio API pricing to avoid unexpected costs.

The knowledge points of the article match the official knowledge files, and you can further learn relevant knowledge. Python entry skill treeHomepageOverview 352,164 people are learning the system