As of November 2022, Twilio no longer provides support for Authy SMS/Voice-only customers. Customers who were also using Authy TOTP or Push prior to March 1, 2023 are still supported. The Authy API is now closed to new customers and will be fully deprecated in the future.
For new development, we encourage you to use the Verify v2 API.
Existing customers will not be impacted at this time until Authy API has reached End of Life. For more information about migration, see Migrating from Authy to Verify for SMS.
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
account_verification_flask/__init__.py
_27from flask import Flask_27from flask_login import LoginManager_27from flask_sqlalchemy import SQLAlchemy_27from flask_bcrypt import Bcrypt_27from account_verification_flask.config import config_env_files_27_27app = Flask(__name__)_27db = SQLAlchemy()_27bcrypt = Bcrypt()_27login_manager = LoginManager()_27_27_27def prepare_app(_27 environment='development', p_db=db, p_bcrypt=bcrypt, p_login_manager=login_manager_27):_27 app.config.from_object(config_env_files[environment])_27_27 p_db.init_app(app)_27 p_bcrypt.init_app(app)_27 p_login_manager.init_app(app)_27 p_login_manager.login_view = 'register'_27 return app_27_27_27prepare_app()_27_27import account_verification_flask.views # noqa F402
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:
_10AUTHY_KEY = 'your_authy_key'_10_10TWILIO_ACCOUNT_SID = 'your_twilio_account_sid'_10TWILIO_AUTH_TOKEN = 'your_twilio_auth_token'_10TWILIO_NUMBER = 'your_twilio_phone_number'_10_10SQLALCHEMY_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.
account_verification_flask/config.py
_41import os_41_41from dotenv import load_dotenv_41_41load_dotenv()_41_41basedir = os.path.abspath(os.path.dirname(__file__))_41_41_41class DefaultConfig(object):_41 SECRET_KEY = os.environ.get('SECRET_KEY', 'secret-key')_41 SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URI')_41 SQLALCHEMY_TRACK_MODIFICATIONS = False_41_41 TWILIO_ACCOUNT_SID = os.environ.get('TWILIO_ACCOUNT_SID', None)_41 TWILIO_API_KEY = os.environ.get('TWILIO_API_KEY', None)_41 TWILIO_API_SECRET = os.environ.get('TWILIO_API_SECRET', None)_41 TWILIO_NUMBER = os.environ.get('TWILIO_NUMBER', None)_41 AUTHY_API_KEY = os.environ.get('AUTHY_API_KEY', None)_41_41 DEBUG = False_41_41_41class DevelopmentConfig(DefaultConfig):_41 SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'dev.sqlite')_41 DEBUG = True_41_41_41class TestConfig(DefaultConfig):_41 SQLALCHEMY_DATABASE_URI = 'sqlite:///:memory:'_41 SQLALCHEMY_ECHO = True_41 DEBUG = True_41 TESTING = True_41 WTF_CSRF_ENABLED = False_41_41_41config_env_files = {_41 'testing': 'account_verification_flask.config.TestConfig',_41 'development': 'account_verification_flask.config.DevelopmentConfig',_41 'production': 'account_verification_flask.config.Default',_41}
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.
account_verification_flask/models/models.py
_41# from flask.ext.login import UserMixin_41from account_verification_flask import db, bcrypt_41_41_41class User(db.Model):_41 __tablename__ = "users"_41_41 id = db.Column(db.Integer, primary_key=True)_41 name = db.Column(db.String, nullable=False)_41 email = db.Column(db.String, nullable=False)_41 password = db.Column(db.String)_41 phone_number = db.Column(db.String, nullable=False)_41 country_code = db.Column(db.String, nullable=False)_41 phone_number_confirmed = db.Column(db.Boolean, nullable=False, default=False)_41 authy_user_id = db.Column(db.String, nullable=True)_41_41 def __init__(self, name, email, password, phone_number, country_code):_41 self.name = name_41 self.email = email_41 self.password = bcrypt.generate_password_hash(password)_41 self.phone_number = phone_number_41 self.country_code = country_code_41 self.phone_number_confirmed = False_41_41 def is_authenticated(self):_41 return True_41_41 def is_active(self):_41 return True_41_41 def is_anonymous(self):_41 return False_41_41 def get_id(self):_41 return str(self.id)_41_41 def __str__(self):_41 return self.name_41_41 def __repr__(self):_41 return f'<User: {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.
account_verification_flask/templates/register.html
_28{% extends "layout.html" %}_28_28{% block content %}_28_28<h1>We're going to be *BEST* friends</h1>_28<p> Thanks for your interest in signing up! Can you tell us a bit about yourself?</p>_28_28_28<form method="POST" class="form-horizontal" role="form">_28 {% from "_formhelpers.html" import render_errors, render_field %}_28 {{ form.csrf_token }}_28 {{ render_errors(form) }}_28 <hr/>_28_28 {{ render_field(form.name, placeholder='Anakin Skywalker') }}_28 {{ render_field(form.email, placeholder='darth@vader.com') }}_28 {{ render_field(form.password) }}_28 {{ render_field(form.country_code, id="authy-countries" ) }}_28 {{ render_field(form.phone_number , type='number') }}_28_28 <div class="form-group">_28 <div class="col-md-offset-2 col-md-10">_28 <input type="submit" class="btn btn-primary" value="Sign Up" />_28 </div>_28 </div>_28</form>_28_28{% 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.
account_verification_flask/views.py
_155from flask import request, flash, g_155from flask_login import login_user, logout_user, current_user_155from account_verification_flask import app, db, login_manager_155from account_verification_flask.forms.forms import (_155 RegisterForm,_155 ResendCodeForm,_155 VerifyCodeForm,_155)_155from account_verification_flask.models.models import User_155from account_verification_flask.services.authy_services import AuthyServices_155from account_verification_flask.services.twilio_services import TwilioServices_155from account_verification_flask.utilities import User_Already_Confirmed_155from account_verification_flask.utilities.view_helpers import view, redirect_to_155import account_verification_flask.utilities_155_155_155@app.route('/')_155@app.route('/home')_155def home():_155 return view('index')_155_155_155@app.route('/register', methods=["GET", "POST"])_155def register():_155 form = RegisterForm()_155 if request.method == 'POST':_155 if form.validate_on_submit():_155_155 if User.query.filter(User.email == form.email.data).count() > 0:_155 form.email.errors.append(_155 account_verification_flask.utilities.User_Email_Already_In_Use_155 )_155 return view('register', form)_155_155 user = User(_155 name=form.name.data,_155 email=form.email.data,_155 password=form.password.data,_155 country_code=form.country_code.data,_155 phone_number=form.phone_number.data,_155 )_155 db.session.add(user)_155 db.session.commit()_155_155 authy_services = AuthyServices()_155 if authy_services.request_phone_confirmation_code(user):_155 db.session.commit()_155 flash(account_verification_flask.utilities.Verification_Code_Sent)_155 return redirect_to('verify', email=form.email.data)_155_155 form.email.errors.append(_155 account_verification_flask.utilities.Verification_Code_Not_Sent_155 )_155_155 else:_155 return view('register', form)_155_155 return view('register', form)_155_155_155@app.route('/verify', methods=["GET", "POST"])_155@app.route('/verify/<email>', methods=["GET"])_155def verify():_155 form = VerifyCodeForm()_155 if request.method == 'POST':_155 if form.validate_on_submit():_155 user = User.query.filter(User.email == form.email.data).first()_155_155 if user is None:_155 form.email.errors.append(_155 account_verification_flask.utilities.User_Not_Found_For_Given_Email_155 )_155 return view('verify_registration_code', form)_155_155 if user.phone_number_confirmed:_155 form.email.errors.append(User_Already_Confirmed)_155 return view('verify_registration_code', form)_155_155 authy_services = AuthyServices()_155 if authy_services.confirm_phone_number(user, form.verification_code.data):_155 user.phone_number_confirmed = True_155 db.session.commit()_155 login_user(user, remember=True)_155 twilio_services = TwilioServices()_155 twilio_services.send_registration_success_sms(_155 "+{0}{1}".format(user.country_code, user.phone_number)_155 )_155 return redirect_to('status')_155 else:_155 form.email.errors.append(_155 account_verification_flask.utilities.Verification_Unsuccessful_155 )_155 return view('verify_registration_code', form)_155 else:_155 form.email.data = request.args.get('email')_155 return view('verify_registration_code', form)_155_155_155@app.route('/resend', methods=["GET", "POST"])_155@app.route('/resend/<email>', methods=["GET"])_155def resend(email=""):_155 form = ResendCodeForm()_155_155 if request.method == 'POST':_155 if form.validate_on_submit():_155 user = User.query.filter(User.email == form.email.data).first()_155_155 if user is None:_155 form.email.errors.append(_155 account_verification_flask.utilities.User_Not_Found_For_Given_Email_155 )_155 return view('resend_confirmation_code', form)_155_155 if user.phone_number_confirmed:_155 form.email.errors.append(_155 account_verification_flask.utilities.User_Already_Confirmed_155 )_155 return view('resend_confirmation_code', form)_155 authy_services = AuthyServices()_155 if authy_services.request_phone_confirmation_code(user):_155 flash(account_verification_flask.utilities.Verification_Code_Resent)_155 return redirect_to('verify', email=form.email.data)_155 else:_155 form.email.errors.append(_155 account_verification_flask.utilities.Verification_Code_Not_Sent_155 )_155 else:_155 form.email.data = email_155_155 return view('resend_confirmation_code', form)_155_155_155@app.route('/status')_155def status():_155 return view('status')_155_155_155@app.route('/logout', methods=["POST"])_155def logout():_155 logout_user()_155 return redirect_to('home')_155_155_155# controller utils_155@app.before_request_155def before_request():_155 g.user = current_user_155_155_155@login_manager.user_loader_155def load_user(user_id):_155 try:_155 return User.query.get(user_id)_155 except Exception:_155 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:
After that (assuming a success!) we redirect the user to a success page.
account_verification_flask/views.py
_155from flask import request, flash, g_155from flask_login import login_user, logout_user, current_user_155from account_verification_flask import app, db, login_manager_155from account_verification_flask.forms.forms import (_155 RegisterForm,_155 ResendCodeForm,_155 VerifyCodeForm,_155)_155from account_verification_flask.models.models import User_155from account_verification_flask.services.authy_services import AuthyServices_155from account_verification_flask.services.twilio_services import TwilioServices_155from account_verification_flask.utilities import User_Already_Confirmed_155from account_verification_flask.utilities.view_helpers import view, redirect_to_155import account_verification_flask.utilities_155_155_155@app.route('/')_155@app.route('/home')_155def home():_155 return view('index')_155_155_155@app.route('/register', methods=["GET", "POST"])_155def register():_155 form = RegisterForm()_155 if request.method == 'POST':_155 if form.validate_on_submit():_155_155 if User.query.filter(User.email == form.email.data).count() > 0:_155 form.email.errors.append(_155 account_verification_flask.utilities.User_Email_Already_In_Use_155 )_155 return view('register', form)_155_155 user = User(_155 name=form.name.data,_155 email=form.email.data,_155 password=form.password.data,_155 country_code=form.country_code.data,_155 phone_number=form.phone_number.data,_155 )_155 db.session.add(user)_155 db.session.commit()_155_155 authy_services = AuthyServices()_155 if authy_services.request_phone_confirmation_code(user):_155 db.session.commit()_155 flash(account_verification_flask.utilities.Verification_Code_Sent)_155 return redirect_to('verify', email=form.email.data)_155_155 form.email.errors.append(_155 account_verification_flask.utilities.Verification_Code_Not_Sent_155 )_155_155 else:_155 return view('register', form)_155_155 return view('register', form)_155_155_155@app.route('/verify', methods=["GET", "POST"])_155@app.route('/verify/<email>', methods=["GET"])_155def verify():_155 form = VerifyCodeForm()_155 if request.method == 'POST':_155 if form.validate_on_submit():_155 user = User.query.filter(User.email == form.email.data).first()_155_155 if user is None:_155 form.email.errors.append(_155 account_verification_flask.utilities.User_Not_Found_For_Given_Email_155 )_155 return view('verify_registration_code', form)_155_155 if user.phone_number_confirmed:_155 form.email.errors.append(User_Already_Confirmed)_155 return view('verify_registration_code', form)_155_155 authy_services = AuthyServices()_155 if authy_services.confirm_phone_number(user, form.verification_code.data):_155 user.phone_number_confirmed = True_155 db.session.commit()_155 login_user(user, remember=True)_155 twilio_services = TwilioServices()_155 twilio_services.send_registration_success_sms(_155 "+{0}{1}".format(user.country_code, user.phone_number)_155 )_155 return redirect_to('status')_155 else:_155 form.email.errors.append(_155 account_verification_flask.utilities.Verification_Unsuccessful_155 )_155 return view('verify_registration_code', form)_155 else:_155 form.email.data = request.args.get('email')_155 return view('verify_registration_code', form)_155_155_155@app.route('/resend', methods=["GET", "POST"])_155@app.route('/resend/<email>', methods=["GET"])_155def resend(email=""):_155 form = ResendCodeForm()_155_155 if request.method == 'POST':_155 if form.validate_on_submit():_155 user = User.query.filter(User.email == form.email.data).first()_155_155 if user is None:_155 form.email.errors.append(_155 account_verification_flask.utilities.User_Not_Found_For_Given_Email_155 )_155 return view('resend_confirmation_code', form)_155_155 if user.phone_number_confirmed:_155 form.email.errors.append(_155 account_verification_flask.utilities.User_Already_Confirmed_155 )_155 return view('resend_confirmation_code', form)_155 authy_services = AuthyServices()_155 if authy_services.request_phone_confirmation_code(user):_155 flash(account_verification_flask.utilities.Verification_Code_Resent)_155 return redirect_to('verify', email=form.email.data)_155 else:_155 form.email.errors.append(_155 account_verification_flask.utilities.Verification_Code_Not_Sent_155 )_155 else:_155 form.email.data = email_155_155 return view('resend_confirmation_code', form)_155_155_155@app.route('/status')_155def status():_155 return view('status')_155_155_155@app.route('/logout', methods=["POST"])_155def logout():_155 logout_user()_155 return redirect_to('home')_155_155_155# controller utils_155@app.before_request_155def before_request():_155 g.user = current_user_155_155_155@login_manager.user_loader_155def load_user(user_id):_155 try:_155 return User.query.get(user_id)_155 except Exception:_155 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?
account_verification_flask/views.py
_155from flask import request, flash, g_155from flask_login import login_user, logout_user, current_user_155from account_verification_flask import app, db, login_manager_155from account_verification_flask.forms.forms import (_155 RegisterForm,_155 ResendCodeForm,_155 VerifyCodeForm,_155)_155from account_verification_flask.models.models import User_155from account_verification_flask.services.authy_services import AuthyServices_155from account_verification_flask.services.twilio_services import TwilioServices_155from account_verification_flask.utilities import User_Already_Confirmed_155from account_verification_flask.utilities.view_helpers import view, redirect_to_155import account_verification_flask.utilities_155_155_155@app.route('/')_155@app.route('/home')_155def home():_155 return view('index')_155_155_155@app.route('/register', methods=["GET", "POST"])_155def register():_155 form = RegisterForm()_155 if request.method == 'POST':_155 if form.validate_on_submit():_155_155 if User.query.filter(User.email == form.email.data).count() > 0:_155 form.email.errors.append(_155 account_verification_flask.utilities.User_Email_Already_In_Use_155 )_155 return view('register', form)_155_155 user = User(_155 name=form.name.data,_155 email=form.email.data,_155 password=form.password.data,_155 country_code=form.country_code.data,_155 phone_number=form.phone_number.data,_155 )_155 db.session.add(user)_155 db.session.commit()_155_155 authy_services = AuthyServices()_155 if authy_services.request_phone_confirmation_code(user):_155 db.session.commit()_155 flash(account_verification_flask.utilities.Verification_Code_Sent)_155 return redirect_to('verify', email=form.email.data)_155_155 form.email.errors.append(_155 account_verification_flask.utilities.Verification_Code_Not_Sent_155 )_155_155 else:_155 return view('register', form)_155_155 return view('register', form)_155_155_155@app.route('/verify', methods=["GET", "POST"])_155@app.route('/verify/<email>', methods=["GET"])_155def verify():_155 form = VerifyCodeForm()_155 if request.method == 'POST':_155 if form.validate_on_submit():_155 user = User.query.filter(User.email == form.email.data).first()_155_155 if user is None:_155 form.email.errors.append(_155 account_verification_flask.utilities.User_Not_Found_For_Given_Email_155 )_155 return view('verify_registration_code', form)_155_155 if user.phone_number_confirmed:_155 form.email.errors.append(User_Already_Confirmed)_155 return view('verify_registration_code', form)_155_155 authy_services = AuthyServices()_155 if authy_services.confirm_phone_number(user, form.verification_code.data):_155 user.phone_number_confirmed = True_155 db.session.commit()_155 login_user(user, remember=True)_155 twilio_services = TwilioServices()_155 twilio_services.send_registration_success_sms(_155 "+{0}{1}".format(user.country_code, user.phone_number)_155 )_155 return redirect_to('status')_155 else:_155 form.email.errors.append(_155 account_verification_flask.utilities.Verification_Unsuccessful_155 )_155 return view('verify_registration_code', form)_155 else:_155 form.email.data = request.args.get('email')_155 return view('verify_registration_code', form)_155_155_155@app.route('/resend', methods=["GET", "POST"])_155@app.route('/resend/<email>', methods=["GET"])_155def resend(email=""):_155 form = ResendCodeForm()_155_155 if request.method == 'POST':_155 if form.validate_on_submit():_155 user = User.query.filter(User.email == form.email.data).first()_155_155 if user is None:_155 form.email.errors.append(_155 account_verification_flask.utilities.User_Not_Found_For_Given_Email_155 )_155 return view('resend_confirmation_code', form)_155_155 if user.phone_number_confirmed:_155 form.email.errors.append(_155 account_verification_flask.utilities.User_Already_Confirmed_155 )_155 return view('resend_confirmation_code', form)_155 authy_services = AuthyServices()_155 if authy_services.request_phone_confirmation_code(user):_155 flash(account_verification_flask.utilities.Verification_Code_Resent)_155 return redirect_to('verify', email=form.email.data)_155 else:_155 form.email.errors.append(_155 account_verification_flask.utilities.Verification_Code_Not_Sent_155 )_155 else:_155 form.email.data = email_155_155 return view('resend_confirmation_code', form)_155_155_155@app.route('/status')_155def status():_155 return view('status')_155_155_155@app.route('/logout', methods=["POST"])_155def logout():_155 logout_user()_155 return redirect_to('home')_155_155_155# controller utils_155@app.before_request_155def before_request():_155 g.user = current_user_155_155_155@login_manager.user_loader_155def load_user(user_id):_155 try:_155 return User.query.get(user_id)_155 except Exception:_155 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.
account_verification_flask/services/authy_services.py
_37import account_verification_flask.utilities_37from account_verification_flask.utilities.settings import AuthySettings_37from authy.api import AuthyApiClient_37_37_37class AuthyServices:_37 authy_client = None_37_37 def __init__(self):_37 if AuthyServices.authy_client is None:_37 AuthyServices.authy_client = AuthyApiClient(AuthySettings.key())_37_37 def request_phone_confirmation_code(self, user):_37 if user is None:_37 raise ValueError(account_verification_flask.utilities.User_Id_Not_Found)_37_37 if user.authy_user_id is None:_37 self._register_user_under_authy(user)_37_37 sms = self.authy_client.users.request_sms(user.authy_user_id, {'force': True})_37 return not sms.ignored()_37_37 def confirm_phone_number(self, user, verification_code):_37 if user is None:_37 raise ValueError(account_verification_flask.utilities.User_Id_Not_Found)_37_37 verification = self.authy_client.tokens.verify(_37 user.authy_user_id, verification_code_37 )_37 return verification.ok()_37_37 def _register_user_under_authy(self, user):_37 authy_user = self.authy_client.users.create(_37 user.email, user.phone_number, user.country_code_37 )_37 if authy_user.ok:_37 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.
account_verification_flask/services/authy_services.py
_37import account_verification_flask.utilities_37from account_verification_flask.utilities.settings import AuthySettings_37from authy.api import AuthyApiClient_37_37_37class AuthyServices:_37 authy_client = None_37_37 def __init__(self):_37 if AuthyServices.authy_client is None:_37 AuthyServices.authy_client = AuthyApiClient(AuthySettings.key())_37_37 def request_phone_confirmation_code(self, user):_37 if user is None:_37 raise ValueError(account_verification_flask.utilities.User_Id_Not_Found)_37_37 if user.authy_user_id is None:_37 self._register_user_under_authy(user)_37_37 sms = self.authy_client.users.request_sms(user.authy_user_id, {'force': True})_37 return not sms.ignored()_37_37 def confirm_phone_number(self, user, verification_code):_37 if user is None:_37 raise ValueError(account_verification_flask.utilities.User_Id_Not_Found)_37_37 verification = self.authy_client.tokens.verify(_37 user.authy_user_id, verification_code_37 )_37 return verification.ok()_37_37 def _register_user_under_authy(self, user):_37 authy_user = self.authy_client.users.create(_37 user.email, user.phone_number, user.country_code_37 )_37 if authy_user.ok:_37 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().
account_verification_flask/services/twilio_services.py
_22import account_verification_flask.utilities_22from account_verification_flask.utilities.settings import TwilioSettings_22from twilio.rest import Client_22_22_22class TwilioServices:_22 twilio_client = None_22_22 def __init__(self):_22 if TwilioServices.twilio_client is None:_22 TwilioServices.twilio_client = Client(_22 TwilioSettings.api_key(),_22 TwilioSettings.api_secret(),_22 TwilioSettings.account_sid(),_22 )_22_22 def send_registration_success_sms(self, to_number):_22 self.twilio_client.messages.create(_22 body=account_verification_flask.utilities.Signup_Complete,_22 to=to_number,_22 from_=TwilioSettings.phone_number(),_22 )
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.