Two Factor Authentication (2FA)

Two factor authentication (commonly abbreviated 2FA) adds an extra layer of security to your user’s account login by requiring two forms of authentication: something your user knows and something they have.

Examples of Two Factor Authentication

Two factor authentication is nothing new. When you use your credit card and are prompted for your billing zip code, that’s 2FA in action. Knowledge factors like your zip code may also be passwords or a personal identification number (PIN). Posession factors like your credit card include (but are not limited to) a physical key, fob, and personal cell phones. Two factor authentication for web applications similarly requires something your user knows (their password) and something they have (their personal mobile phone).

How Does Two Factor Authentication Keep Your Users Secure?

The classic authentication approach for web applications requires a user to enter a username and password. However, things like password reuse, poorly encrypted passwords, social hacking, and hacked databases make even a secure password vulnerable. By requiring users to add a second factor to their authentication flow, an account with a compromised password will still be secure.

Mobile phone 2FA has become the industry standard, as most people carry their mobile phones at all times. It’s a user-friendly flow, and dynamically generated passcodes are safe to use and users can receive special tokens through SMS or a dedicated app, such as Twilio’s Authy.

How Does Two Factor Authentication Work?

Log a user in with two factor authentication

When a user signs up or logs in to your application, a numeric code is sent to their mobile device either via SMS or through an authenticator app. Two benefits of using an authenticator app is that it provides a constantly rotating set of codes your users can use whenever needed, and does not require a cellular or internet connection. Only after the user enters the correct numeric code in your application’s login flow are they authenticated.

Adding Two Factor Authentication to Your Application

2FA SMS with Authy

 

There are a wide variety of ways to add two factor authentication to your application.  TOTP (Time-based One-Time Password) verification tokens may be sent to your user’s device via SMS, voice call, or authenticator app. By using Twilio and the Authy API, this implementation is greatly simplified and can boil down to just a few lines of code.

Loading Code Samples...
Language
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
account_verification_flask/views.py
Verify a User Account with Authy Services

account_verification_flask/views.py

Where to Next?

Ready to add 2FA to your application with Twilio? Here are some resources to get you started:

Quick and Easy 2FA: Adding Authy to a NodeJS App

Two Factor Authentication in Rails 4 with Devise, Authy and Puppies

Account Verification with Authy, Java and Servlets

Twilio's Authy Documentation

We can't wait to see what you build!