Ready to add Authy user account verification to your Flask application? Don't worry, this will be the easiest thing you do all day.
Here's how it all works at a high level:
To get this done, you'll be working with the following Twilio-powered APIs:
Authy REST API
Twilio REST API
from flask import Flask
from flask.ext.login import LoginManager
from flask.ext.sqlalchemy import SQLAlchemy
from flask.ext.bcrypt import Bcrypt
from account_verification_flask.config import config_env_files
db = SQLAlchemy()
bcrypt = Bcrypt()
login_manager = LoginManager()
def create_app(config_name='development', p_db=db, p_bcrypt=bcrypt, p_login_manager=login_manager):
new_app = Flask(__name__)
new_app.config.from_object(config_env_files[config_name])
p_db.init_app(new_app)
p_bcrypt.init_app(new_app)
p_login_manager.init_app(new_app)
p_login_manager.login_view = 'register'
return new_app
app = create_app()
import account_verification_flask.views
All of this can be done in under a half an hour with the simplicity and power of Authy and Twilio. Let's get started!
For this application we'll be using the The Twilio Python Helper Library and the Python Client for Authy API. We require some configuration from your side before we can begin.
Edit the DevelopmentConfig
class constant values located in the account_verification_flask/config.py
file:
AUTHY_KEY = 'your_authy_key'
TWILIO_ACCOUNT_SID = 'your_twilio_account_sid'
TWILIO_AUTH_TOKEN = 'your_twilio_auth_token'
TWILIO_NUMBER = 'your_twilio_phone_number'
SQLALCHEMY_DATABASE_URI = 'sqlite://'
Note that you have to replace the placeholders your_twilio_account_sid
, your_twilio_auth_token
, your_twilio_phone_number
and your_authy_key
with your information. You can find all of those parameters (and more) in your Twilio Account Console and your Authy dashboard.
class DefaultConfig(object):
SECRET_KEY = '%^!@@*!&$8xdfdirunb52438#(&^874@#^&*($@*(@&^@)(&*)Y_)((+'
SQLALCHEMY_DATABASE_URI = 'sqlite://'
class DevelopmentConfig(DefaultConfig):
AUTHY_KEY = 'your_authy_key'
TWILIO_ACCOUNT_SID = 'your_twilio_account_sid'
TWILIO_AUTH_TOKEN = 'your_twilio_auth_token'
TWILIO_NUMBER = 'your_twilio_phone_number'
SQLALCHEMY_DATABASE_URI = 'sqlite://'
DEBUG = True
class TestConfig(DefaultConfig):
SQLALCHEMY_ECHO = True
DEBUG = True
TESTING = True
WTF_CSRF_ENABLED = False
config_env_files = {
'test': 'account_verification_flask.config.TestConfig',
'development': 'account_verification_flask.config.DevelopmentConfig',
}
Now that we've got the setup boilerplate out of the way, let's take a look at the User
model.
The User Model for this tutorial is pretty straight-forward. Note the new variable authy_user_id
, which is implemented for storing the user's Authy identification token.
We'll be using the Flask-Login library for our user session management. To integrate this library into our code we need to implement a few properties and methods, then we're good to go.
# from flask.ext.login import UserMixin
from account_verification_flask import db, bcrypt
class User(db.Model):
__tablename__ = "users"
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String, nullable=False)
email = db.Column(db.String, nullable=False)
password = db.Column(db.String)
phone_number = db.Column(db.String, nullable=False)
country_code = db.Column(db.String, nullable=False)
phone_number_confirmed = db.Column(db.Boolean, nullable=False, default=False)
authy_user_id = db.Column(db.String, nullable=True)
def __init__(self, name, email, password, phone_number, country_code):
self.name = name
self.email = email
self.password = bcrypt.generate_password_hash(password)
self.phone_number = phone_number
self.country_code = country_code
self.phone_number_confirmed = False
def is_authenticated(self):
return True
def is_active(self):
return True
def is_anonymous(self):
return False
def get_id(self):
return unicode(self.id)
def __unicode__(self):
return self.name
def __repr__(self):
return '<User %r>' % (self.name)
Pretty simple User
model, right? Next we're going to visit the registration form on the client side.
In order to validate the user's account and register the user, we need a mobile number with a country code. We can then use Authy to send a verification code via SMS.
In this example we're validating and rendering the forms with the WTForms library. This allows us to define the forms as classes inside Python.
{% extends "layout.html" %}
{% block content %}
<h1>We're going to be *BEST* friends</h1>
<p> Thanks for your interest in signing up! Can you tell us a bit about yourself?</p>
<form method="POST" class="form-horizontal" role="form">
{% from "_formhelpers.html" import render_errors, render_field %}
{{ form.csrf_token }}
{{ render_errors(form) }}
<hr/>
{{ render_field(form.name, placeholder='Anakin Skywalker') }}
{{ render_field(form.email, placeholder='darth@vader.com') }}
{{ render_field(form.password) }}
{{ render_field(form.country_code, id="authy-countries" ) }}
{{ render_field(form.phone_number , type='number') }}
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" class="btn btn-primary" value="Sign Up" />
</div>
</div>
</form>
{% endblock %}
That's it for the client side. Now let's look at what happens when the user submits the form.
Next our controller stores the new user, registers them with Authy's API, and requests a new verification code.
from datetime import datetime
from flask import session, request, flash, url_for, abort, g
from flask.ext.login import login_user, logout_user, current_user, login_required
from account_verification_flask import app, db, login_manager
from account_verification_flask.forms.forms import RegisterForm, ResendCodeForm, VerifyCodeForm
from account_verification_flask.models.models import User
from account_verification_flask.services.authy_services import AuthyServices
from account_verification_flask.services.twilio_services import TwilioServices
from account_verification_flask.utilities.view_helpers import *
import account_verification_flask.utilities
@app.route('/')
@app.route('/home')
def home():
return view('index')
@app.route('/register', methods=["GET", "POST"])
def register():
form = RegisterForm()
if request.method == 'POST':
if form.validate_on_submit():
if User.query.filter(User.email == form.email.data).count() > 0:
form.email.errors.append(account_verification_flask.utilities.User_Email_Already_In_Use)
return view('register', form)
user = User(
name=form.name.data,
email=form.email.data,
password=form.password.data,
country_code=form.country_code.data,
phone_number=form.phone_number.data
)
db.session.add(user)
db.session.commit()
authy_services = AuthyServices()
if authy_services.request_phone_confirmation_code(user):
db.session.commit()
flash(account_verification_flask.utilities.Verification_Code_Sent)
return redirect_to('verify', email=form.email.data)
form.email.errors.append(account_verification_flask.utilities.Verification_Code_Not_Sent)
else:
return view('register', form)
return view('register', form)
@app.route('/verify', methods=["GET", "POST"])
@app.route('/verify/<email>', methods=["GET"])
def verify():
form = VerifyCodeForm()
if request.method == 'POST':
if form.validate_on_submit():
user = User.query.filter(User.email == form.email.data).first()
if user == None:
form.email.errors.append(account_verification_flask.utilities.User_Not_Found_For_Given_Email)
return view('verify_registration_code', form)
if user.phone_number_confirmed:
form.email.errors.append(User_Already_Confirmed)
return view('verify_registration_code', form)
authy_services = AuthyServices()
if authy_services.confirm_phone_number(user, form.verification_code.data):
user.phone_number_confirmed = True
db.session.commit()
login_user(user, remember=True)
twilio_services = TwilioServices()
twilio_services.send_registration_success_sms("+{0}{1}".format(user.country_code, user.phone_number))
return redirect_to('status')
else:
form.email.errors.append(account_verification_flask.utilities.Verification_Unsuccessful)
return view('verify_registration_code', form)
else:
form.email.data = request.args.get('email')
return view('verify_registration_code', form)
@app.route('/resend', methods=["GET", "POST"])
@app.route('/resend/<email>', methods=["GET"])
def resend(email=""):
form = ResendCodeForm()
if request.method == 'POST':
if form.validate_on_submit():
user = User.query.filter(User.email == form.email.data).first()
if user == None:
form.email.errors.append(account_verification_flask.utilities.User_Not_Found_For_Given_Email)
return view('resend_confirmation_code', form)
if user.phone_number_confirmed:
form.email.errors.append(account_verification_flask.utilities.User_Already_Confirmed)
return view('resend_confirmation_code', form)
authy_services = AuthyServices()
if authy_services.request_phone_confirmation_code(user):
flash(account_verification_flask.utilities.Verification_Code_Resent)
return redirect_to('verify', email=form.email.data)
else:
form.email.errors.append(account_verification_flask.utilities.Verification_Code_Not_Sent)
else:
form.email.data = email
return view('resend_confirmation_code', form)
@app.route('/status')
def status():
return view('status')
@app.route('/logout', methods=["POST"])
def logout():
logout_user()
return redirect_to('home')
# controller utils
@app.before_request
def before_request():
g.user = current_user
@login_manager.user_loader
def load_user(id):
try:
return User.query.get(id)
except:
return None
Next we'll set up our application to complete our user verification.
On the server we first check that the email belongs to a user that we haven't yet verified.
The process then has two critical steps:
Communicate with Authy's API to check if the given code is correct.
Send a confirmation SMS to the user using Twilio's API.
After that (assuming a success!) we redirect the user to a success page.
from datetime import datetime
from flask import session, request, flash, url_for, abort, g
from flask.ext.login import login_user, logout_user, current_user, login_required
from account_verification_flask import app, db, login_manager
from account_verification_flask.forms.forms import RegisterForm, ResendCodeForm, VerifyCodeForm
from account_verification_flask.models.models import User
from account_verification_flask.services.authy_services import AuthyServices
from account_verification_flask.services.twilio_services import TwilioServices
from account_verification_flask.utilities.view_helpers import *
import account_verification_flask.utilities
@app.route('/')
@app.route('/home')
def home():
return view('index')
@app.route('/register', methods=["GET", "POST"])
def register():
form = RegisterForm()
if request.method == 'POST':
if form.validate_on_submit():
if User.query.filter(User.email == form.email.data).count() > 0:
form.email.errors.append(account_verification_flask.utilities.User_Email_Already_In_Use)
return view('register', form)
user = User(
name=form.name.data,
email=form.email.data,
password=form.password.data,
country_code=form.country_code.data,
phone_number=form.phone_number.data
)
db.session.add(user)
db.session.commit()
authy_services = AuthyServices()
if authy_services.request_phone_confirmation_code(user):
db.session.commit()
flash(account_verification_flask.utilities.Verification_Code_Sent)
return redirect_to('verify', email=form.email.data)
form.email.errors.append(account_verification_flask.utilities.Verification_Code_Not_Sent)
else:
return view('register', form)
return view('register', form)
@app.route('/verify', methods=["GET", "POST"])
@app.route('/verify/<email>', methods=["GET"])
def verify():
form = VerifyCodeForm()
if request.method == 'POST':
if form.validate_on_submit():
user = User.query.filter(User.email == form.email.data).first()
if user == None:
form.email.errors.append(account_verification_flask.utilities.User_Not_Found_For_Given_Email)
return view('verify_registration_code', form)
if user.phone_number_confirmed:
form.email.errors.append(User_Already_Confirmed)
return view('verify_registration_code', form)
authy_services = AuthyServices()
if authy_services.confirm_phone_number(user, form.verification_code.data):
user.phone_number_confirmed = True
db.session.commit()
login_user(user, remember=True)
twilio_services = TwilioServices()
twilio_services.send_registration_success_sms("+{0}{1}".format(user.country_code, user.phone_number))
return redirect_to('status')
else:
form.email.errors.append(account_verification_flask.utilities.Verification_Unsuccessful)
return view('verify_registration_code', form)
else:
form.email.data = request.args.get('email')
return view('verify_registration_code', form)
@app.route('/resend', methods=["GET", "POST"])
@app.route('/resend/<email>', methods=["GET"])
def resend(email=""):
form = ResendCodeForm()
if request.method == 'POST':
if form.validate_on_submit():
user = User.query.filter(User.email == form.email.data).first()
if user == None:
form.email.errors.append(account_verification_flask.utilities.User_Not_Found_For_Given_Email)
return view('resend_confirmation_code', form)
if user.phone_number_confirmed:
form.email.errors.append(account_verification_flask.utilities.User_Already_Confirmed)
return view('resend_confirmation_code', form)
authy_services = AuthyServices()
if authy_services.request_phone_confirmation_code(user):
flash(account_verification_flask.utilities.Verification_Code_Resent)
return redirect_to('verify', email=form.email.data)
else:
form.email.errors.append(account_verification_flask.utilities.Verification_Code_Not_Sent)
else:
form.email.data = email
return view('resend_confirmation_code', form)
@app.route('/status')
def status():
return view('status')
@app.route('/logout', methods=["POST"])
def logout():
logout_user()
return redirect_to('home')
# controller utils
@app.before_request
def before_request():
g.user = current_user
@login_manager.user_loader
def load_user(id):
try:
return User.query.get(id)
except:
return None
What happens if the message was never sent, didn't arrive, or can't be found? Let's look at how to handle those scenarios next.
The form for re-sending the code is a single line, so let's skip that detail for this tutorial. Instead, let's just take a look at the controller function for resending verifications.
This controller loads the User
associated with the request and then uses the same Authy API method we used earlier to resend the code. Pretty straightforward, right?
from datetime import datetime
from flask import session, request, flash, url_for, abort, g
from flask.ext.login import login_user, logout_user, current_user, login_required
from account_verification_flask import app, db, login_manager
from account_verification_flask.forms.forms import RegisterForm, ResendCodeForm, VerifyCodeForm
from account_verification_flask.models.models import User
from account_verification_flask.services.authy_services import AuthyServices
from account_verification_flask.services.twilio_services import TwilioServices
from account_verification_flask.utilities.view_helpers import *
import account_verification_flask.utilities
@app.route('/')
@app.route('/home')
def home():
return view('index')
@app.route('/register', methods=["GET", "POST"])
def register():
form = RegisterForm()
if request.method == 'POST':
if form.validate_on_submit():
if User.query.filter(User.email == form.email.data).count() > 0:
form.email.errors.append(account_verification_flask.utilities.User_Email_Already_In_Use)
return view('register', form)
user = User(
name=form.name.data,
email=form.email.data,
password=form.password.data,
country_code=form.country_code.data,
phone_number=form.phone_number.data
)
db.session.add(user)
db.session.commit()
authy_services = AuthyServices()
if authy_services.request_phone_confirmation_code(user):
db.session.commit()
flash(account_verification_flask.utilities.Verification_Code_Sent)
return redirect_to('verify', email=form.email.data)
form.email.errors.append(account_verification_flask.utilities.Verification_Code_Not_Sent)
else:
return view('register', form)
return view('register', form)
@app.route('/verify', methods=["GET", "POST"])
@app.route('/verify/<email>', methods=["GET"])
def verify():
form = VerifyCodeForm()
if request.method == 'POST':
if form.validate_on_submit():
user = User.query.filter(User.email == form.email.data).first()
if user == None:
form.email.errors.append(account_verification_flask.utilities.User_Not_Found_For_Given_Email)
return view('verify_registration_code', form)
if user.phone_number_confirmed:
form.email.errors.append(User_Already_Confirmed)
return view('verify_registration_code', form)
authy_services = AuthyServices()
if authy_services.confirm_phone_number(user, form.verification_code.data):
user.phone_number_confirmed = True
db.session.commit()
login_user(user, remember=True)
twilio_services = TwilioServices()
twilio_services.send_registration_success_sms("+{0}{1}".format(user.country_code, user.phone_number))
return redirect_to('status')
else:
form.email.errors.append(account_verification_flask.utilities.Verification_Unsuccessful)
return view('verify_registration_code', form)
else:
form.email.data = request.args.get('email')
return view('verify_registration_code', form)
@app.route('/resend', methods=["GET", "POST"])
@app.route('/resend/<email>', methods=["GET"])
def resend(email=""):
form = ResendCodeForm()
if request.method == 'POST':
if form.validate_on_submit():
user = User.query.filter(User.email == form.email.data).first()
if user == None:
form.email.errors.append(account_verification_flask.utilities.User_Not_Found_For_Given_Email)
return view('resend_confirmation_code', form)
if user.phone_number_confirmed:
form.email.errors.append(account_verification_flask.utilities.User_Already_Confirmed)
return view('resend_confirmation_code', form)
authy_services = AuthyServices()
if authy_services.request_phone_confirmation_code(user):
flash(account_verification_flask.utilities.Verification_Code_Resent)
return redirect_to('verify', email=form.email.data)
else:
form.email.errors.append(account_verification_flask.utilities.Verification_Code_Not_Sent)
else:
form.email.data = email
return view('resend_confirmation_code', form)
@app.route('/status')
def status():
return view('status')
@app.route('/logout', methods=["POST"])
def logout():
logout_user()
return redirect_to('home')
# controller utils
@app.before_request
def before_request():
g.user = current_user
@login_manager.user_loader
def load_user(id):
try:
return User.query.get(id)
except:
return None
Let's take a step back and see how we can use Authy to resend a verification code to an unverified user.
In order to end up with a cleaner and decoupled design we'll encapsulate all of Authy's related features in an AuthyService
. This class will hold a shared class instance of the AuthyApiClient
class.
Once the user has an authyId
we can send a verification code to that user's mobile phone.
import account_verification_flask.utilities
from account_verification_flask.utilities.settings import AuthySettings
from authy.api import AuthyApiClient
class AuthyServices:
authy_client = None
def __init__(self):
if AuthyServices.authy_client == None:
AuthyServices.authy_client = AuthyApiClient(AuthySettings.key())
def request_phone_confirmation_code(self, user):
if user == None:
raise ValueError(account_verification_flask.utilities.User_Id_Not_Found)
if user.authy_user_id == None:
self._register_user_under_authy(user)
sms = AuthyServices.authy_client.users.request_sms(user.authy_user_id, {'force': True})
return not sms.ignored()
def confirm_phone_number(self, user, verification_code):
if user == None:
raise ValueError(account_verification_flask.utilities.User_Id_Not_Found)
verification = AuthyServices.authy_client.tokens.verify(user.authy_user_id, verification_code)
return verification.ok()
def _register_user_under_authy(self, user):
authy_user = AuthyServices.authy_client.users.create(user.email, user.phone_number, user.country_code)
if authy_user.ok:
user.authy_user_id = authy_user.id
When our user is created successfully via the form we have implemented, we send a token to the user's mobile phone asking them to verify their account in our controller. When the code is sent, we redirect our users to another page where they can enter the received token, completing the verification process.
Authy provides us with a tokens.verify
method that allows us to pass a user id
and token
. In this case we just need to check that the API request was successful and, if so, set a verified
flag on the user.
import account_verification_flask.utilities
from account_verification_flask.utilities.settings import AuthySettings
from authy.api import AuthyApiClient
class AuthyServices:
authy_client = None
def __init__(self):
if AuthyServices.authy_client == None:
AuthyServices.authy_client = AuthyApiClient(AuthySettings.key())
def request_phone_confirmation_code(self, user):
if user == None:
raise ValueError(account_verification_flask.utilities.User_Id_Not_Found)
if user.authy_user_id == None:
self._register_user_under_authy(user)
sms = AuthyServices.authy_client.users.request_sms(user.authy_user_id, {'force': True})
return not sms.ignored()
def confirm_phone_number(self, user, verification_code):
if user == None:
raise ValueError(account_verification_flask.utilities.User_Id_Not_Found)
verification = AuthyServices.authy_client.tokens.verify(user.authy_user_id, verification_code)
return verification.ok()
def _register_user_under_authy(self, user):
authy_user = AuthyServices.authy_client.users.create(user.email, user.phone_number, user.country_code)
if authy_user.ok:
user.authy_user_id = authy_user.id
That's it for token verification! Let's provide a nice user onboarding experience, and send a confirmation message to our new user.
Just as we did for our Authy client, we create a single instance of the Twilio REST API helper. It will be called twilio_client
in this example.
After that, it's straightforward - send an SMS using the Twilio Python helper library to the same number we used in messages.create().
import account_verification_flask.utilities
from account_verification_flask.utilities.settings import TwilioSettings
from twilio.rest import Client
class TwilioServices:
twilio_client = None
def __init__(self):
if TwilioServices.twilio_client == None:
TwilioServices.twilio_client = Client(TwilioSettings.account_sid(), TwilioSettings.auth_token())
def send_registration_success_sms(self, to_number):
message = TwilioServices.twilio_client.messages.create(
body=account_verification_flask.utilities.Signup_Complete,
to=to_number,
from_=TwilioSettings.phone_number())
Congratulations! You've successfully verified new user accounts with Authy. Where can we take it from here?
In one simple tutorial, we've implemented account verification with Authy and Twilio, allowing your users to confirm accounts with their phone number! Now it's on you - let us know what you build on Twitter, and check out these other tutorials:
Use Twilio to automate the process of reaching out to your customers in advance of an upcoming appointment.
Two-Factor Authentication with Authy
Use Twilio and Twilio-powered Authy OneTouch to implement two-factor authentication (2FA) in your web app.
We all do sometimes; code is hard. Get help now from our support team, or lean on the wisdom of the crowd browsing the Twilio tag on Stack Overflow.
from flask import Flask
from flask.ext.login import LoginManager
from flask.ext.sqlalchemy import SQLAlchemy
from flask.ext.bcrypt import Bcrypt
from account_verification_flask.config import config_env_files
db = SQLAlchemy()
bcrypt = Bcrypt()
login_manager = LoginManager()
def create_app(config_name='development', p_db=db, p_bcrypt=bcrypt, p_login_manager=login_manager):
new_app = Flask(__name__)
new_app.config.from_object(config_env_files[config_name])
p_db.init_app(new_app)
p_bcrypt.init_app(new_app)
p_login_manager.init_app(new_app)
p_login_manager.login_view = 'register'
return new_app
app = create_app()
import account_verification_flask.views
class DefaultConfig(object):
SECRET_KEY = '%^!@@*!&$8xdfdirunb52438#(&^874@#^&*($@*(@&^@)(&*)Y_)((+'
SQLALCHEMY_DATABASE_URI = 'sqlite://'
class DevelopmentConfig(DefaultConfig):
AUTHY_KEY = 'your_authy_key'
TWILIO_ACCOUNT_SID = 'your_twilio_account_sid'
TWILIO_AUTH_TOKEN = 'your_twilio_auth_token'
TWILIO_NUMBER = 'your_twilio_phone_number'
SQLALCHEMY_DATABASE_URI = 'sqlite://'
DEBUG = True
class TestConfig(DefaultConfig):
SQLALCHEMY_ECHO = True
DEBUG = True
TESTING = True
WTF_CSRF_ENABLED = False
config_env_files = {
'test': 'account_verification_flask.config.TestConfig',
'development': 'account_verification_flask.config.DevelopmentConfig',
}
# from flask.ext.login import UserMixin
from account_verification_flask import db, bcrypt
class User(db.Model):
__tablename__ = "users"
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String, nullable=False)
email = db.Column(db.String, nullable=False)
password = db.Column(db.String)
phone_number = db.Column(db.String, nullable=False)
country_code = db.Column(db.String, nullable=False)
phone_number_confirmed = db.Column(db.Boolean, nullable=False, default=False)
authy_user_id = db.Column(db.String, nullable=True)
def __init__(self, name, email, password, phone_number, country_code):
self.name = name
self.email = email
self.password = bcrypt.generate_password_hash(password)
self.phone_number = phone_number
self.country_code = country_code
self.phone_number_confirmed = False
def is_authenticated(self):
return True
def is_active(self):
return True
def is_anonymous(self):
return False
def get_id(self):
return unicode(self.id)
def __unicode__(self):
return self.name
def __repr__(self):
return '<User %r>' % (self.name)
{% extends "layout.html" %}
{% block content %}
<h1>We're going to be *BEST* friends</h1>
<p> Thanks for your interest in signing up! Can you tell us a bit about yourself?</p>
<form method="POST" class="form-horizontal" role="form">
{% from "_formhelpers.html" import render_errors, render_field %}
{{ form.csrf_token }}
{{ render_errors(form) }}
<hr/>
{{ render_field(form.name, placeholder='Anakin Skywalker') }}
{{ render_field(form.email, placeholder='darth@vader.com') }}
{{ render_field(form.password) }}
{{ render_field(form.country_code, id="authy-countries" ) }}
{{ render_field(form.phone_number , type='number') }}
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" class="btn btn-primary" value="Sign Up" />
</div>
</div>
</form>
{% endblock %}
from datetime import datetime
from flask import session, request, flash, url_for, abort, g
from flask.ext.login import login_user, logout_user, current_user, login_required
from account_verification_flask import app, db, login_manager
from account_verification_flask.forms.forms import RegisterForm, ResendCodeForm, VerifyCodeForm
from account_verification_flask.models.models import User
from account_verification_flask.services.authy_services import AuthyServices
from account_verification_flask.services.twilio_services import TwilioServices
from account_verification_flask.utilities.view_helpers import *
import account_verification_flask.utilities
@app.route('/')
@app.route('/home')
def home():
return view('index')
@app.route('/register', methods=["GET", "POST"])
def register():
form = RegisterForm()
if request.method == 'POST':
if form.validate_on_submit():
if User.query.filter(User.email == form.email.data).count() > 0:
form.email.errors.append(account_verification_flask.utilities.User_Email_Already_In_Use)
return view('register', form)
user = User(
name=form.name.data,
email=form.email.data,
password=form.password.data,
country_code=form.country_code.data,
phone_number=form.phone_number.data
)
db.session.add(user)
db.session.commit()
authy_services = AuthyServices()
if authy_services.request_phone_confirmation_code(user):
db.session.commit()
flash(account_verification_flask.utilities.Verification_Code_Sent)
return redirect_to('verify', email=form.email.data)
form.email.errors.append(account_verification_flask.utilities.Verification_Code_Not_Sent)
else:
return view('register', form)
return view('register', form)
@app.route('/verify', methods=["GET", "POST"])
@app.route('/verify/<email>', methods=["GET"])
def verify():
form = VerifyCodeForm()
if request.method == 'POST':
if form.validate_on_submit():
user = User.query.filter(User.email == form.email.data).first()
if user == None:
form.email.errors.append(account_verification_flask.utilities.User_Not_Found_For_Given_Email)
return view('verify_registration_code', form)
if user.phone_number_confirmed:
form.email.errors.append(User_Already_Confirmed)
return view('verify_registration_code', form)
authy_services = AuthyServices()
if authy_services.confirm_phone_number(user, form.verification_code.data):
user.phone_number_confirmed = True
db.session.commit()
login_user(user, remember=True)
twilio_services = TwilioServices()
twilio_services.send_registration_success_sms("+{0}{1}".format(user.country_code, user.phone_number))
return redirect_to('status')
else:
form.email.errors.append(account_verification_flask.utilities.Verification_Unsuccessful)
return view('verify_registration_code', form)
else:
form.email.data = request.args.get('email')
return view('verify_registration_code', form)
@app.route('/resend', methods=["GET", "POST"])
@app.route('/resend/<email>', methods=["GET"])
def resend(email=""):
form = ResendCodeForm()
if request.method == 'POST':
if form.validate_on_submit():
user = User.query.filter(User.email == form.email.data).first()
if user == None:
form.email.errors.append(account_verification_flask.utilities.User_Not_Found_For_Given_Email)
return view('resend_confirmation_code', form)
if user.phone_number_confirmed:
form.email.errors.append(account_verification_flask.utilities.User_Already_Confirmed)
return view('resend_confirmation_code', form)
authy_services = AuthyServices()
if authy_services.request_phone_confirmation_code(user):
flash(account_verification_flask.utilities.Verification_Code_Resent)
return redirect_to('verify', email=form.email.data)
else:
form.email.errors.append(account_verification_flask.utilities.Verification_Code_Not_Sent)
else:
form.email.data = email
return view('resend_confirmation_code', form)
@app.route('/status')
def status():
return view('status')
@app.route('/logout', methods=["POST"])
def logout():
logout_user()
return redirect_to('home')
# controller utils
@app.before_request
def before_request():
g.user = current_user
@login_manager.user_loader
def load_user(id):
try:
return User.query.get(id)
except:
return None
from datetime import datetime
from flask import session, request, flash, url_for, abort, g
from flask.ext.login import login_user, logout_user, current_user, login_required
from account_verification_flask import app, db, login_manager
from account_verification_flask.forms.forms import RegisterForm, ResendCodeForm, VerifyCodeForm
from account_verification_flask.models.models import User
from account_verification_flask.services.authy_services import AuthyServices
from account_verification_flask.services.twilio_services import TwilioServices
from account_verification_flask.utilities.view_helpers import *
import account_verification_flask.utilities
@app.route('/')
@app.route('/home')
def home():
return view('index')
@app.route('/register', methods=["GET", "POST"])
def register():
form = RegisterForm()
if request.method == 'POST':
if form.validate_on_submit():
if User.query.filter(User.email == form.email.data).count() > 0:
form.email.errors.append(account_verification_flask.utilities.User_Email_Already_In_Use)
return view('register', form)
user = User(
name=form.name.data,
email=form.email.data,
password=form.password.data,
country_code=form.country_code.data,
phone_number=form.phone_number.data
)
db.session.add(user)
db.session.commit()
authy_services = AuthyServices()
if authy_services.request_phone_confirmation_code(user):
db.session.commit()
flash(account_verification_flask.utilities.Verification_Code_Sent)
return redirect_to('verify', email=form.email.data)
form.email.errors.append(account_verification_flask.utilities.Verification_Code_Not_Sent)
else:
return view('register', form)
return view('register', form)
@app.route('/verify', methods=["GET", "POST"])
@app.route('/verify/<email>', methods=["GET"])
def verify():
form = VerifyCodeForm()
if request.method == 'POST':
if form.validate_on_submit():
user = User.query.filter(User.email == form.email.data).first()
if user == None:
form.email.errors.append(account_verification_flask.utilities.User_Not_Found_For_Given_Email)
return view('verify_registration_code', form)
if user.phone_number_confirmed:
form.email.errors.append(User_Already_Confirmed)
return view('verify_registration_code', form)
authy_services = AuthyServices()
if authy_services.confirm_phone_number(user, form.verification_code.data):
user.phone_number_confirmed = True
db.session.commit()
login_user(user, remember=True)
twilio_services = TwilioServices()
twilio_services.send_registration_success_sms("+{0}{1}".format(user.country_code, user.phone_number))
return redirect_to('status')
else:
form.email.errors.append(account_verification_flask.utilities.Verification_Unsuccessful)
return view('verify_registration_code', form)
else:
form.email.data = request.args.get('email')
return view('verify_registration_code', form)
@app.route('/resend', methods=["GET", "POST"])
@app.route('/resend/<email>', methods=["GET"])
def resend(email=""):
form = ResendCodeForm()
if request.method == 'POST':
if form.validate_on_submit():
user = User.query.filter(User.email == form.email.data).first()
if user == None:
form.email.errors.append(account_verification_flask.utilities.User_Not_Found_For_Given_Email)
return view('resend_confirmation_code', form)
if user.phone_number_confirmed:
form.email.errors.append(account_verification_flask.utilities.User_Already_Confirmed)
return view('resend_confirmation_code', form)
authy_services = AuthyServices()
if authy_services.request_phone_confirmation_code(user):
flash(account_verification_flask.utilities.Verification_Code_Resent)
return redirect_to('verify', email=form.email.data)
else:
form.email.errors.append(account_verification_flask.utilities.Verification_Code_Not_Sent)
else:
form.email.data = email
return view('resend_confirmation_code', form)
@app.route('/status')
def status():
return view('status')
@app.route('/logout', methods=["POST"])
def logout():
logout_user()
return redirect_to('home')
# controller utils
@app.before_request
def before_request():
g.user = current_user
@login_manager.user_loader
def load_user(id):
try:
return User.query.get(id)
except:
return None
from datetime import datetime
from flask import session, request, flash, url_for, abort, g
from flask.ext.login import login_user, logout_user, current_user, login_required
from account_verification_flask import app, db, login_manager
from account_verification_flask.forms.forms import RegisterForm, ResendCodeForm, VerifyCodeForm
from account_verification_flask.models.models import User
from account_verification_flask.services.authy_services import AuthyServices
from account_verification_flask.services.twilio_services import TwilioServices
from account_verification_flask.utilities.view_helpers import *
import account_verification_flask.utilities
@app.route('/')
@app.route('/home')
def home():
return view('index')
@app.route('/register', methods=["GET", "POST"])
def register():
form = RegisterForm()
if request.method == 'POST':
if form.validate_on_submit():
if User.query.filter(User.email == form.email.data).count() > 0:
form.email.errors.append(account_verification_flask.utilities.User_Email_Already_In_Use)
return view('register', form)
user = User(
name=form.name.data,
email=form.email.data,
password=form.password.data,
country_code=form.country_code.data,
phone_number=form.phone_number.data
)
db.session.add(user)
db.session.commit()
authy_services = AuthyServices()
if authy_services.request_phone_confirmation_code(user):
db.session.commit()
flash(account_verification_flask.utilities.Verification_Code_Sent)
return redirect_to('verify', email=form.email.data)
form.email.errors.append(account_verification_flask.utilities.Verification_Code_Not_Sent)
else:
return view('register', form)
return view('register', form)
@app.route('/verify', methods=["GET", "POST"])
@app.route('/verify/<email>', methods=["GET"])
def verify():
form = VerifyCodeForm()
if request.method == 'POST':
if form.validate_on_submit():
user = User.query.filter(User.email == form.email.data).first()
if user == None:
form.email.errors.append(account_verification_flask.utilities.User_Not_Found_For_Given_Email)
return view('verify_registration_code', form)
if user.phone_number_confirmed:
form.email.errors.append(User_Already_Confirmed)
return view('verify_registration_code', form)
authy_services = AuthyServices()
if authy_services.confirm_phone_number(user, form.verification_code.data):
user.phone_number_confirmed = True
db.session.commit()
login_user(user, remember=True)
twilio_services = TwilioServices()
twilio_services.send_registration_success_sms("+{0}{1}".format(user.country_code, user.phone_number))
return redirect_to('status')
else:
form.email.errors.append(account_verification_flask.utilities.Verification_Unsuccessful)
return view('verify_registration_code', form)
else:
form.email.data = request.args.get('email')
return view('verify_registration_code', form)
@app.route('/resend', methods=["GET", "POST"])
@app.route('/resend/<email>', methods=["GET"])
def resend(email=""):
form = ResendCodeForm()
if request.method == 'POST':
if form.validate_on_submit():
user = User.query.filter(User.email == form.email.data).first()
if user == None:
form.email.errors.append(account_verification_flask.utilities.User_Not_Found_For_Given_Email)
return view('resend_confirmation_code', form)
if user.phone_number_confirmed:
form.email.errors.append(account_verification_flask.utilities.User_Already_Confirmed)
return view('resend_confirmation_code', form)
authy_services = AuthyServices()
if authy_services.request_phone_confirmation_code(user):
flash(account_verification_flask.utilities.Verification_Code_Resent)
return redirect_to('verify', email=form.email.data)
else:
form.email.errors.append(account_verification_flask.utilities.Verification_Code_Not_Sent)
else:
form.email.data = email
return view('resend_confirmation_code', form)
@app.route('/status')
def status():
return view('status')
@app.route('/logout', methods=["POST"])
def logout():
logout_user()
return redirect_to('home')
# controller utils
@app.before_request
def before_request():
g.user = current_user
@login_manager.user_loader
def load_user(id):
try:
return User.query.get(id)
except:
return None
import account_verification_flask.utilities
from account_verification_flask.utilities.settings import AuthySettings
from authy.api import AuthyApiClient
class AuthyServices:
authy_client = None
def __init__(self):
if AuthyServices.authy_client == None:
AuthyServices.authy_client = AuthyApiClient(AuthySettings.key())
def request_phone_confirmation_code(self, user):
if user == None:
raise ValueError(account_verification_flask.utilities.User_Id_Not_Found)
if user.authy_user_id == None:
self._register_user_under_authy(user)
sms = AuthyServices.authy_client.users.request_sms(user.authy_user_id, {'force': True})
return not sms.ignored()
def confirm_phone_number(self, user, verification_code):
if user == None:
raise ValueError(account_verification_flask.utilities.User_Id_Not_Found)
verification = AuthyServices.authy_client.tokens.verify(user.authy_user_id, verification_code)
return verification.ok()
def _register_user_under_authy(self, user):
authy_user = AuthyServices.authy_client.users.create(user.email, user.phone_number, user.country_code)
if authy_user.ok:
user.authy_user_id = authy_user.id
import account_verification_flask.utilities
from account_verification_flask.utilities.settings import AuthySettings
from authy.api import AuthyApiClient
class AuthyServices:
authy_client = None
def __init__(self):
if AuthyServices.authy_client == None:
AuthyServices.authy_client = AuthyApiClient(AuthySettings.key())
def request_phone_confirmation_code(self, user):
if user == None:
raise ValueError(account_verification_flask.utilities.User_Id_Not_Found)
if user.authy_user_id == None:
self._register_user_under_authy(user)
sms = AuthyServices.authy_client.users.request_sms(user.authy_user_id, {'force': True})
return not sms.ignored()
def confirm_phone_number(self, user, verification_code):
if user == None:
raise ValueError(account_verification_flask.utilities.User_Id_Not_Found)
verification = AuthyServices.authy_client.tokens.verify(user.authy_user_id, verification_code)
return verification.ok()
def _register_user_under_authy(self, user):
authy_user = AuthyServices.authy_client.users.create(user.email, user.phone_number, user.country_code)
if authy_user.ok:
user.authy_user_id = authy_user.id
import account_verification_flask.utilities
from account_verification_flask.utilities.settings import TwilioSettings
from twilio.rest import Client
class TwilioServices:
twilio_client = None
def __init__(self):
if TwilioServices.twilio_client == None:
TwilioServices.twilio_client = Client(TwilioSettings.account_sid(), TwilioSettings.auth_token())
def send_registration_success_sms(self, to_number):
message = TwilioServices.twilio_client.messages.create(
body=account_verification_flask.utilities.Signup_Complete,
to=to_number,
from_=TwilioSettings.phone_number())