Skip to content

Instantly share code, notes, and snippets.

@mosampaio
Last active September 1, 2016 15:12
Show Gist options
  • Save mosampaio/2ce95ddec134c976ad77a94d2ba9feae to your computer and use it in GitHub Desktop.
Save mosampaio/2ce95ddec134c976ad77a94d2ba9feae to your computer and use it in GitHub Desktop.
Simple Phone Verification with Twilio, Python, SQLite, and jQuery Raw

How to run it locally?

  • Install the dependencies.
pip install -r requirements
  • Create the database.
python app.py
  • In app.py, configure the variables accordingly: TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN, TWILIO_PHONE_NUMBER, TWIML_URL.

  • Start the server and check it out at http://localhost:5000.

FLASK_APP=app.py python -m flask run
from flask import Flask
from flask import request
from flask import send_file
from flask_sqlalchemy import SQLAlchemy
from uuid import uuid1
from random import randint
from twilio.rest import TwilioRestClient
import json
import os
from twilio import twiml
app = Flask(__name__)
basedir = os.path.abspath(os.path.dirname(__file__))
database_uri = 'sqlite:///' + os.path.join(basedir, 'dev.sqlite')
app.config['SQLALCHEMY_DATABASE_URI'] = database_uri
db = SQLAlchemy(app)
# Get these credentials from http://twilio.com/user/account
TWILIO_ACCOUNT_SID = 'my-account-sid'
TWILIO_AUTH_TOKEN = 'my-auth-token'
TWILIO_PHONE_NUMBER = 'my-phone-number'
# Your URL should be accessible through the web.
# If you are testing locally, you can use 'ngrok' to expose it.
# Remember to append the /twiml/ suffix.
TWIML_URL = 'https://www.example.org/twiml/'
class Number(db.Model):
id = db.Column(db.String(36), primary_key=True)
phone_number = db.Column(db.String(20), unique=True)
verification_code = db.Column(db.String(6))
verified = db.Column(db.Boolean)
def __init__(self, phone_number, verification_code):
self.id = str(uuid1())
self.phone_number = phone_number
self.verification_code = verification_code
self.verified = False
def __repr__(self):
return '<Number %r>' % self.id
@app.route('/', methods=['GET'])
def index_route():
return send_file('index.html')
@app.route('/call/', methods=['POST'])
def call_route():
verification_code = randint(100000, 999999)
phone_number = request.form['phone_number']
Number.query.delete()
number = Number(phone_number, verification_code)
db.session.add(number)
db.session.commit()
client = TwilioRestClient(TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN)
client.calls.create(to=phone_number, url=TWIML_URL,
from_=TWILIO_PHONE_NUMBER)
return json.dumps({'verification_code': verification_code})
@app.route('/twiml/', methods=['POST'])
def twiml_route():
code = request.form.get('Digits', None)
r = twiml.Response()
if not code:
with r.gather(numDigits=6) as g:
g.say('Please enter your verification code.')
else:
phone_number = request.form['Called']
number = Number.query.filter_by(phone_number=phone_number,
verification_code=code).first()
if not number:
with r.gather(numDigits=6) as g:
g.say('Verification code incorrect, please try again.')
else:
number.verified = True
db.session.add(number)
db.session.commit()
r.say('Thank you! Your phone number has been verified.')
return str(r)
@app.route('/status/', methods=['POST'])
def status_route():
number = Number.query.filter_by(
phone_number=request.form['phone_number'], verified=True).first()
return json.dumps({'status': 'verified' if number else 'unverified'})
if __name__ == '__main__':
db.create_all()
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Phone Verification by Twilio</title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function(){
$("#enter_number_form").submit(function(e) {
e.preventDefault();
initiateCall();
});
});
function initiateCall() {
$.post("/call/", $("#enter_number_form").serialize(), function(data) {
showCodeForm(data.verification_code);
}, "json");
checkStatus();
}
function showCodeForm(code) {
$("#verification_code").text(code);
$("#verify_code").fadeIn();
$("#enter_number_form").fadeOut();
}
function checkStatus() {
$.post("/status/", $("#enter_number_form").serialize(), function(data) {
updateStatus(data.status);
}, "json");
}
function updateStatus(current) {
if (current === "unverified") {
$("#status").append(".");
setTimeout(checkStatus, 3000);
} else {
$("#status").text("Verified!");
}
}
</script>
</head>
<body>
<form id="enter_number_form">
<p>Enter your phone number:</p>
<p><input type="text" name="phone_number" id="phone_number" /></p>
<p><input type="submit" name="submit" value="Verify" /></p>
</form>
<div id="verify_code" style="display: none;">
<p>Calling you now.</p>
<p>When prompted, enter the verification code:</p>
<h1 id="verification_code"></h1>
<p><strong id="status">Waiting...</strong></p>
</div>
</body>
</html>
# Flask
Flask==0.11
twilio==5.4.0
Flask-SQLAlchemy==2.1
@acamino
Copy link

acamino commented Sep 1, 2016

@mosampaio, could you remove the trailing slashes from the routes in the route decorators?
e.g. https://gist.github.com/mosampaio/2ce95ddec134c976ad77a94d2ba9feae/#file-app-py-L50

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment