OTP Verification System (Twilio Verify)¶
This project demonstrates how to build a scalable OTP (One-Time Password) generation and verification system using Twilio Verify.
It follows a modular structure in Go and an equivalent implementation in Python using Flask.
Prerequisites (Twilio Setup)¶
Before running the project:
- Create a Twilio account.
- Get your Account SID and Auth Token from the Console.
- Navigate to Verify → Services and create a new service.
- Copy the generated Service SID.
Golang Implementation¶
This implementation uses:
ginframework- Official
twilio-goSDK
Project Structure¶
/cmd/main.go
/cmd/.env
/api/config.go
/api/handler.go
/api/helper.go
/api/route.go
/api/service.go
/data/model.go
Environment Variables (cmd/.env)¶
Data Models (data/model.go)¶
package data
type OTPData struct {
PhoneNumber string `json:"phone_number" validate:"required"`
}
type VerifyData struct {
User string `json:"user" validate:"required"`
Code string `json:"code" validate:"required"`
}
Twilio Service Layer (api/service.go)¶
package api
import (
"github.com/twilio/twilio-go"
verify "github.com/twilio/twilio-go/rest/verify/v2"
)
func twilioClient() *twilio.RestClient {
return twilio.NewRestClientWithParams(twilio.ClientParams{
Username: envAccountSID(),
Password: envAuthToken(),
})
}
func TwilioSendOTP(phoneNumber string) (*verify.VerifyV2Verification, error) {
client := twilioClient()
params := &verify.CreateVerificationParams{}
params.SetTo(phoneNumber)
params.SetChannel("sms")
resp, err := client.VerifyV2.CreateVerification(envServicesID(), params)
return resp, err
}
func TwilioVerifyOTP(phoneNumber string, code string) (*verify.VerifyV2VerificationCheck, error) {
client := twilioClient()
params := &verify.CreateVerificationCheckParams{}
params.SetTo(phoneNumber)
params.SetCode(code)
resp, err := client.VerifyV2.CreateVerificationCheck(envServicesID(), params)
return resp, err
}
Main Entry (cmd/main.go)¶
package main
import (
"github.com/gin-gonic/gin"
"your-module-path/api"
)
func main() {
router := gin.Default()
app := api.Config{Router: router}
app.Routes()
router.Run(":8000")
}
Python Implementation¶
This version uses:
- Flask
- Twilio Python Helper Library
- python-dotenv
Installation¶
app.py¶
import os
from flask import Flask, request, jsonify
from dotenv import load_dotenv
from twilio.rest import Client
from twilio.base.exceptions import TwilioRestException
load_dotenv()
app = Flask(__name__)
ACCOUNT_SID = os.getenv("TWILIO_ACCOUNT_SID")
AUTH_TOKEN = os.getenv("TWILIO_AUTH_TOKEN")
VERIFY_SERVICE_SID = os.getenv("TWILIO_SERVICES_ID")
client = Client(ACCOUNT_SID, AUTH_TOKEN)
@app.route('/otp', methods=['POST'])
def send_otp():
data = request.get_json()
phone_number = data.get('phone_number')
try:
verification = client.verify.v2.services(VERIFY_SERVICE_SID) \
.verifications \
.create(to=phone_number, channel='sms')
return jsonify({
"status": 200,
"message": "OTP sent successfully",
"data": verification.sid
}), 200
except TwilioRestException as e:
return jsonify({"status": 500, "message": str(e)}), 500
@app.route('/verifyOTP', methods=['POST'])
def verify_otp():
data = request.get_json()
phone_number = data.get('user')
code = data.get('code')
try:
verification_check = client.verify.v2.services(VERIFY_SERVICE_SID) \
.verification_checks \
.create(to=phone_number, code=code)
if verification_check.status == "approved":
return jsonify({
"status": 200,
"message": "OTP verified successfully"
}), 200
else:
return jsonify({"status": 400, "message": "Invalid OTP"}), 400
except TwilioRestException as e:
return jsonify({"status": 500, "message": str(e)}), 500
if __name__ == '__main__':
app.run(port=8000)
API Testing¶
Send OTP¶
curl -X POST http://localhost:8000/otp \
-H "Content-Type: application/json" \
-d '{"phone_number": "+1234567890"}'
Verify OTP¶
curl -X POST http://localhost:8000/verifyOTP \
-H "Content-Type: application/json" \
-d '{"user": "+1234567890", "code": "123456"}'