<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ Two-factor authentication - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ Two-factor authentication - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Tue, 23 Jun 2026 22:45:22 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/two-factor-authentication/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Implement Two-Factor Authentication with PyOTP and Google Authenticator in Your Flask App ]]>
                </title>
                <description>
                    <![CDATA[ Two-Factor Authentication, or 2FA, is like having an extra lock on the door to your online accounts. Instead of just using a password, 2FA adds another layer of security. It's a bit like needing both a key and a special code to open a vault. Think of... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-implement-two-factor-authentication-in-your-flask-app/</link>
                <guid isPermaLink="false">66ba0e98102ebf67c0a6d42c</guid>
                
                    <category>
                        <![CDATA[ authentication ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Flask Framework ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Two-factor authentication ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ashutosh Krishna ]]>
                </dc:creator>
                <pubDate>Mon, 27 Nov 2023 21:41:12 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/11/2fa-tutorial.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Two-Factor Authentication, or 2FA, is like having an extra lock on the door to your online accounts. Instead of just using a password, 2FA adds another layer of security. It's a bit like needing both a key and a special code to open a vault.</p>
<p>Think of it as a shield for your accounts. Passwords can sometimes be guessed or stolen, but with 2FA, even if someone gets your password, they'd still need that extra code or device to get in. It's an extra step that makes your accounts much harder for hackers to break into.</p>
<p>So, let's explore how to set up this extra layer of protection using PyOTP and Google Authenticator in your Flask app. </p>
<h3 id="heading-table-of-contents">Table of Contents:</h3>
<ol>
<li><a class="post-section-overview" href="#heading-overview-of-pyotp-and-google-authenticator">Overview of PyOTP and Google Authenticator</a></li>
<li><a class="post-section-overview" href="#heading-two-factor-authentication-workflow-in-our-application">Two-Factor Authentication Workflow in Our Application</a></li>
<li><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></li>
<li><a class="post-section-overview" href="#heading-get-your-tools-ready">Get Your Tools Ready</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-the-project">How to Set Up the Project</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-blueprints-for-accounts-and-core">How to Create Blueprints for Accounts and Core</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-a-user-model">How to Create a User Model</a></li>
<li><a class="post-section-overview" href="#heading-how-to-add-flask-login">How to Add Flask-Login</a></li>
<li><a class="post-section-overview" href="#heading-how-to-add-templates-and-static-files">How to Add Templates and Static Files</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-the-homepage">How to Create the Homepage</a></li>
<li><a class="post-section-overview" href="#heading-how-to-implement-user-registration">How to Implement User Registration</a></li>
<li>[How to Implement User Login](#<h2 id="how-to-implement-user-login"><strong>How to Implement User Login</strong></h2>)</li>
<li><a class="post-section-overview" href="#heading-how-to-log-out-the-users">How to Log Out the Users</a></li>
<li><a class="post-section-overview" href="#heading-how-to-add-the-setup-2fa-page">How to Add the Setup 2FA Page</a></li>
<li><a class="post-section-overview" href="#heading-how-to-add-a-2fa-verification-page">How to Add a 2FA Verification Page</a></li>
<li><a class="post-section-overview" href="#heading-how-to-run-the-completed-app-for-the-first-time">How to Run the Completed App for the First Time</a></li>
<li><a class="post-section-overview" href="#heading-wrapping-up">Wrapping Up</a></li>
</ol>
<h2 id="heading-overview-of-pyotp-and-google-authenticator">Overview of PyOTP and Google Authenticator</h2>
<p>PyOTP is a Python library that's incredibly handy for generating Time-based One-Time Passwords (TOTP) and HMAC-based One-Time Passwords (HOTP). Its primary role revolves around creating these unique, time-sensitive codes that add an extra layer of security to user accounts. </p>
<p>By integrating PyOTP into your Flask application, you can easily implement Two-Factor Authentication (2FA) by generating and verifying these OTPs.</p>
<p>If you're new to PyOTP or would like a refresher on its functionalities, I recommend reviewing my previous <a target="_blank" href="https://blog.ashutoshkrris.in/how-to-generate-otps-using-pyotp-in-python">guide on PyOTP</a>. This understanding will be beneficial as we get into the integration of PyOTP within your Flask application for Two-Factor Authentication (2FA).</p>
<p>Google Authenticator, on the other hand, stands out as one of the most widely used OTP generator apps available. It functions as a secure platform for generating time-based OTPs, compatible with various services and applications supporting 2FA. Users can easily set up Google Authenticator on their devices to generate these time-sensitive codes, adding an extra level of security to their accounts.</p>
<h2 id="heading-two-factor-authentication-workflow-in-our-application">Two-Factor Authentication Workflow in Our Application</h2>
<p>Here's a breakdown of the flow of two-factor authentication in our application:</p>
<ol>
<li><strong>Registration with 2FA Setup</strong>: When users sign up on our website, they're prompted to set up an extra layer of security—2FA. This involves scanning a QR code using an authenticator app, such as Google Authenticator, to link their account securely.</li>
<li><strong>Login Initiation</strong>: When users return to log in, they start by entering their usual email/username and password combo to access their account.</li>
<li><strong>Extra Security Check</strong>: Before granting access, our website throws in an additional hurdle: users need to provide an OTP (One-Time Password) displayed on their authenticator app. This ensures they're not just entering the password but also confirming their identity with a unique, time-sensitive code.</li>
<li><strong>Validation and Authorization</strong>: The user inputs the received OTP into our platform. The system then double-checks this OTP against the expected code, validating the information. If the OTP matches, it's like handing over the secret handshake, granting the user access to their account.</li>
</ol>
<p>This seamless back-and-forth between passwords, authenticator apps, and unique codes ensures that only the rightful account owner can access the precious content behind the digital doors of your website.</p>
<p>If you also enjoy visual learning, here's a fancy video showing how the app does its thing.</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/qzLcbq5-UNA" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p>Now, let's get to some coding!</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Before you get started with the tutorial, make sure you have the following requirements satisfied:</p>
<ul>
<li>Working knowledge of Python</li>
<li>Python 3.8+ installed on your system</li>
<li>Basic knowledge of <a target="_blank" href="https://ashutoshkrris.hashnode.dev/getting-started-with-flask">Flask</a> and <a target="_blank" href="https://ashutoshkrris.hashnode.dev/how-to-use-blueprints-to-organize-your-flask-apps">Flask Blueprints</a></li>
<li>Knowledge of <a target="_blank" href="https://blog.ashutoshkrris.in/how-to-set-up-basic-user-authentication-in-a-flask-app">basic authentication in Flask</a> (optional)</li>
</ul>
<h2 id="heading-get-your-tools-ready"><strong>Get Your Tools Ready</strong></h2>
<p>You'll need a few external libraries for this project. Let's learn more about them and install them one by one.</p>
<p>But before we install them, let's create a virtual environment and activate it.</p>
<p>First, start with creating the project directory and navigating to it like this:</p>
<pre><code class="lang-bash">mkdir flask-two-factor-auth
ccd flask-two-factor-auth
</code></pre>
<p>We are going to create a virtual environment using <code>venv</code>. Python now ships with a pre-installed <code>venv</code> library. So, to create a virtual environment, you can use the below command:</p>
<pre><code class="lang-bash">python -m venv env
</code></pre>
<p>The above command will create a virtual environment named env. Now, we need to activate the environment using this command:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">source</span> env/Scripts/activate
</code></pre>
<p>To verify if the environment has been activated or not, you can see <code>(env)</code> in your terminal. Now, we can install the libraries.</p>
<ul>
<li><a target="_blank" href="https://flask.palletsprojects.com/en/2.2.x/">Flask</a> is a simple, easy-to-use microframework for Python that helps you build scalable and secure web applications.</li>
<li><a target="_blank" href="https://flask-login.readthedocs.io/en/latest/">Flask-Login</a> provides user session management for Flask. It handles the common tasks of logging in, logging out, and remembering your users’ sessions over extended periods of time.</li>
<li><a target="_blank" href="https://flask-bcrypt.readthedocs.io/en/1.0.1/">Flask-Bcrypt</a> is a Flask extension that provides bcrypt hashing utilities for your application.</li>
<li><a target="_blank" href="https://flask-wtf.readthedocs.io/en/1.0.x/">Flask-WTF</a> is a simple integration of Flask and WTForms that helps you create forms in Flask.</li>
<li><a target="_blank" href="https://flask-migrate.readthedocs.io/en/latest/">Flask-Migrate</a> is an extension that handles SQLAlchemy database migrations for Flask applications using Alembic. The database operations are made available through the Flask command-line interface.</li>
<li><a target="_blank" href="https://flask-sqlalchemy.palletsprojects.com/en/2.x/">Flask-SQLAlchemy</a> is an extension for Flask that adds support for SQLAlchemy to your application. It helps you simplify things using SQLAlchemy with Flask by giving you useful defaults and extra helpers that make it easier to perform common tasks.</li>
<li><a target="_blank" href="https://blog.ashutoshkrris.in/how-to-generate-otps-using-pyotp-in-python">PyOTP</a> helps you generate OTPs using Time-based OTP (TOTP) and HMAC-based OTP (HOTP) algorithms effortlessly.</li>
<li><a target="_blank" href="https://pypi.org/project/qrcode/">QRCode</a> helps you generate QR Codes in Python</li>
<li><a target="_blank" href="https://pypi.org/project/python-decouple/">Python Decouple</a> helps you use environment variables in your Python project.</li>
</ul>
<p>To install the above-mentioned libraries all in one go, run the following command:</p>
<pre><code class="lang-bash">pip install Flask Flask-Login Flask-Bcrypt Flask-WTF FLask-Migrate Flask-SQLAlchemy pyotp qrcode python-decouple
</code></pre>
<h2 id="heading-how-to-set-up-the-project"><strong>How to Set Up the Project</strong></h2>
<p>Let’s start by creating a <code>src</code> directory:</p>
<pre><code class="lang-bash">mkdir src
</code></pre>
<p>The first file will be the <code>__init__.py</code> file for the project:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> decouple <span class="hljs-keyword">import</span> config
<span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> Flask
<span class="hljs-keyword">from</span> flask_bcrypt <span class="hljs-keyword">import</span> Bcrypt
<span class="hljs-keyword">from</span> flask_migrate <span class="hljs-keyword">import</span> Migrate
<span class="hljs-keyword">from</span> flask_sqlalchemy <span class="hljs-keyword">import</span> SQLAlchemy

app = Flask(__name__)
app.config.from_object(config(<span class="hljs-string">"APP_SETTINGS"</span>))

bcrypt = Bcrypt(app)
db = SQLAlchemy(app)
migrate = Migrate(app, db)

<span class="hljs-comment"># Registering blueprints</span>
<span class="hljs-keyword">from</span> src.accounts.views <span class="hljs-keyword">import</span> accounts_bp
<span class="hljs-keyword">from</span> src.core.views <span class="hljs-keyword">import</span> core_bp

app.register_blueprint(accounts_bp)
app.register_blueprint(core_bp)
</code></pre>
<p>In the above script, we created a Flask app called <code>app</code> . We use the <code>__name__</code> argument to indicate the app's module or package so that Flask knows where to find other files such as templates. We also set the configuration of the app using an environment variable called <code>APP_SETTINGS</code>. We'll export it later.</p>
<p>To use Flask-Bcrypt, Flask-SQLAlchemy, and Flask-Migrate in our application, we just need to create objects of the <code>Bcrypt</code>, <code>SQLAlchemy</code> and <code>Migrate</code> classes from the <code>flask_bcrypt</code>, <code>flask_sqlalchemy</code> and, <code>flask_migrate</code> libraries, respectively.</p>
<p>We've also registered blueprints called <code>accounts_bp</code> and <code>core_bp</code> in the application. We'll define them later in the tutorial.</p>
<p>In the root directory of the project (that is, outside the <code>src</code> directory), create a file called <code>config.py</code>. We'll store the configurations for the project in this file. Within the file, add the following content:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> decouple <span class="hljs-keyword">import</span> config

DATABASE_URI = config(<span class="hljs-string">"DATABASE_URL"</span>)
<span class="hljs-keyword">if</span> DATABASE_URI.startswith(<span class="hljs-string">"postgres://"</span>):
    DATABASE_URI = DATABASE_URI.replace(<span class="hljs-string">"postgres://"</span>, <span class="hljs-string">"postgresql://"</span>, <span class="hljs-number">1</span>)


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Config</span>(<span class="hljs-params">object</span>):</span>
    DEBUG = <span class="hljs-literal">False</span>
    TESTING = <span class="hljs-literal">False</span>
    CSRF_ENABLED = <span class="hljs-literal">True</span>
    SECRET_KEY = config(<span class="hljs-string">"SECRET_KEY"</span>, default=<span class="hljs-string">"guess-me"</span>)
    SQLALCHEMY_DATABASE_URI = DATABASE_URI
    SQLALCHEMY_TRACK_MODIFICATIONS = <span class="hljs-literal">False</span>
    BCRYPT_LOG_ROUNDS = <span class="hljs-number">13</span>
    WTF_CSRF_ENABLED = <span class="hljs-literal">True</span>
    DEBUG_TB_ENABLED = <span class="hljs-literal">False</span>
    DEBUG_TB_INTERCEPT_REDIRECTS = <span class="hljs-literal">False</span>
    APP_NAME = config(<span class="hljs-string">"APP_NAME"</span>)


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DevelopmentConfig</span>(<span class="hljs-params">Config</span>):</span>
    DEVELOPMENT = <span class="hljs-literal">True</span>
    DEBUG = <span class="hljs-literal">True</span>
    WTF_CSRF_ENABLED = <span class="hljs-literal">False</span>
    DEBUG_TB_ENABLED = <span class="hljs-literal">True</span>


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TestingConfig</span>(<span class="hljs-params">Config</span>):</span>
    TESTING = <span class="hljs-literal">True</span>
    DEBUG = <span class="hljs-literal">True</span>
    SQLALCHEMY_DATABASE_URI = <span class="hljs-string">"sqlite:///testdb.sqlite"</span>
    BCRYPT_LOG_ROUNDS = <span class="hljs-number">1</span>
    WTF_CSRF_ENABLED = <span class="hljs-literal">False</span>


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ProductionConfig</span>(<span class="hljs-params">Config</span>):</span>
    DEBUG = <span class="hljs-literal">False</span>
    DEBUG_TB_ENABLED = <span class="hljs-literal">False</span>
</code></pre>
<p>In the above script, we have created a <code>Config</code> class and defined various attributes inside that. Also, we have created different child classes (as per different stages of development) that inherit the <code>Config</code> class.</p>
<p>Notice that we're using a few environment variables like <code>SECRET_KEY</code>, <code>DATABASE_URL</code>, and <code>APP_NAME</code>. Create a file named <code>.env</code> in the root directory and add the following content there:</p>
<pre><code class="lang-python">export SECRET_KEY=fdkjshfhjsdfdskfdsfdcbsjdkfdsdf
export DEBUG=<span class="hljs-literal">True</span>
export APP_SETTINGS=config.DevelopmentConfig
export DATABASE_URL=sqlite:///db.sqlite
export FLASK_APP=src
export FLASK_DEBUG=<span class="hljs-number">1</span>
export APP_NAME=<span class="hljs-string">"Flask User Authentication App"</span>
</code></pre>
<p>Apart from the <code>SECRET_KEY</code> , <code>DATABASE_URL</code> and <code>APP_NAME</code>, we've also exported <code>APP_SETTINGS</code>, <code>DEBUG</code>, <code>FLASK_APP</code>, and <code>FLASK_DEBUG</code>.</p>
<p>The <code>APP_SETTINGS</code> refers to one of the classes we created in the <code>config.py</code> file. We set it to the current stage of the project.</p>
<p>The value of <code>FLASK_APP</code> is the name of the package we have created. Since the app is in the development stage, you can set the values of <code>DEBUG</code> and <code>FLASK_DEBUG</code> to <code>True</code> and <code>1</code>, respectively.</p>
<p>Run the following command to export all the environment variables from the <code>.env</code> file:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">source</span> .env
</code></pre>
<p>Next, we'll create a CLI application of the app so that we can later add custom commands if required.</p>
<p>Create a <code>manage.py</code> file in the root directory of the application and add the following code:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> flask.cli <span class="hljs-keyword">import</span> FlaskGroup

<span class="hljs-keyword">from</span> src <span class="hljs-keyword">import</span> app

cli = FlaskGroup(app)


<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>:
    cli()
</code></pre>
<p>Now, your basic application is ready. You can run it using the following command:</p>
<pre><code class="lang-bash">python manage.py run
</code></pre>
<p>Your file structure should look like below as of now:</p>
<pre><code class="lang-bash">flask-two-factor-auth/
├── src/
│   └── __init__.py
├── .env
├── config.py
└── manage.py
</code></pre>
<h2 id="heading-how-to-create-blueprints-for-accounts-and-core"><strong>How to Create Blueprints for Accounts and Core</strong></h2>
<p>As mentioned earlier, you'll use the concepts of blueprints in the project. Let's create two blueprints – <code>accounts_bp</code> and <code>core_bp</code> – in this section.</p>
<p>First create a directory called <code>accounts</code> like this:</p>
<pre><code class="lang-bash">mkdir accounts
<span class="hljs-built_in">cd</span> accounts
</code></pre>
<p>Next, add an empty <code>__init__.py</code> file to covert it into a Python package. Now, create a <code>views.py</code> file inside the package where you'll store all your routes related to user authentication.</p>
<pre><code class="lang-bash">touch __init__.py views.py
</code></pre>
<p>Add the following code inside the <code>views.py</code> file:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> Blueprint

accounts_bp = Blueprint(<span class="hljs-string">"accounts"</span>, __name__)
</code></pre>
<p>In the above script, you have created a blueprint called <code>accounts_bp</code> for the <code>accounts</code> package.</p>
<p>Similarly, you can create a <code>core</code> package in the root directory, and add a <code>views.py</code> file.</p>
<pre><code class="lang-bash">mkdir core
<span class="hljs-built_in">cd</span> core
touch __init__.py views.py
</code></pre>
<p>Now, add the following code inside the <code>views.py</code> file:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> Blueprint

core_bp = Blueprint(<span class="hljs-string">"core"</span>, __name__)
</code></pre>
<p>Note: If you're new to Flask Blueprints, make sure you go through <a target="_blank" href="https://ashutoshkrris.hashnode.dev/how-to-use-blueprints-to-organize-your-flask-apps">this tutorial</a> to learn more about how it works.</p>
<p>Now, your file structure should look like what you see below:</p>
<pre><code class="lang-bash">flask-two-factor-auth/
├── src/
│   ├── accounts/
│   │   ├── __init__.py
│   │   └── views.py
│   ├── core/
│   │   ├── __init__.py
│   │   └── views.py
│   └── __init__.py
├── .env
├── config.py
└── manage.py
</code></pre>
<h2 id="heading-how-to-create-a-user-model"><strong>How to Create a User Model</strong></h2>
<p>Let's create a <code>models.py</code> file inside the <code>accounts</code> package.</p>
<pre><code class="lang-bash">touch src/accounts/models.py
</code></pre>
<p>Inside the <code>models.py</code> file, add the following code:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> datetime <span class="hljs-keyword">import</span> datetime

<span class="hljs-keyword">import</span> pyotp
<span class="hljs-keyword">from</span> flask_login <span class="hljs-keyword">import</span> UserMixin

<span class="hljs-keyword">from</span> src <span class="hljs-keyword">import</span> bcrypt, db
<span class="hljs-keyword">from</span> config <span class="hljs-keyword">import</span> Config


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span>(<span class="hljs-params">db.Model</span>):</span>

    __tablename__ = <span class="hljs-string">"users"</span>

    id = db.Column(db.Integer, primary_key=<span class="hljs-literal">True</span>)
    username = db.Column(db.String, unique=<span class="hljs-literal">True</span>, nullable=<span class="hljs-literal">False</span>)
    password = db.Column(db.String, nullable=<span class="hljs-literal">False</span>)
    created_at = db.Column(db.DateTime, nullable=<span class="hljs-literal">False</span>)
    is_two_factor_authentication_enabled = db.Column(
        db.Boolean, nullable=<span class="hljs-literal">False</span>, default=<span class="hljs-literal">False</span>)
    secret_token = db.Column(db.String, unique=<span class="hljs-literal">True</span>)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, username, password</span>):</span>
        self.username = username
        self.password = bcrypt.generate_password_hash(password)
        self.created_at = datetime.now()
        self.secret_token = pyotp.random_base32()

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_authentication_setup_uri</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-keyword">return</span> pyotp.totp.TOTP(self.secret_token).provisioning_uri(
            name=self.username, issuer_name=Config.APP_NAME)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">is_otp_valid</span>(<span class="hljs-params">self, user_otp</span>):</span>
        totp = pyotp.parse_uri(self.get_authentication_setup_uri())
        <span class="hljs-keyword">return</span> totp.verify(user_otp)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__repr__</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-keyword">return</span> <span class="hljs-string">f"&lt;user <span class="hljs-subst">{self.username}</span>&gt;"</span>
</code></pre>
<p>In the above code, you created a <code>User</code> model by inheriting the <code>db.Model</code> class. The <code>User</code> model consists of the following fields:</p>
<ul>
<li><code>id</code>: stores the primary key for the <code>users</code> table</li>
<li><code>username</code>: stores the username of the user</li>
<li><code>password</code>: stores the hashed password of the user</li>
<li><code>created_at</code>: stores the timestamp when the user was created</li>
<li><code>is_two_factor_authentication_enabled</code>: boolean flag that stores whether the user has activated two-factor authentication. Default value is <code>False</code>.</li>
<li><code>secret_token</code>: stores a unique token generated for each user, essential for implementing two-factor authentication.</li>
</ul>
<p>The constructor initializes the <code>User</code> object upon instantiation by accepting <code>username</code> and <code>password</code> parameters. It hashes the provided password using <code>bcrypt.generate_password_hash(password)</code>, records the current timestamp as the <code>created_at</code> value, and generates a unique <code>secret_token</code> using <code>pyotp.random_base32()</code> for 2FA setup.</p>
<p>The <code>get_authentication_setup_uri()</code> method generates a setup URI used by authenticator apps like Google Authenticator. It constructs a URI containing the user's username and the application's name (<code>Config.APP_NAME</code>) necessary for setting up two-factor authentication. The basic format of the URI is:</p>
<pre><code class="lang-bash">otpauth://totp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&amp;issuer=Example
</code></pre>
<p>where, alice@google.com is the username of the user and Example is the application's name.</p>
<p>Next up, the <code>is_otp_valid()</code> method verifies the one-time password (OTP) entered by the user during login. It parses the setup URI generated earlier, checks the validity of the provided OTP (<code>user_otp</code>), and returns <code>True</code> if the OTP matches, ensuring secure authentication.</p>
<p>Finally, the <code>__repr__</code> method provides a string representation of the <code>User</code> object, displaying the associated username when an instance of the class is printed or represented as a string.</p>
<h2 id="heading-how-to-add-flask-login"><strong>How to Add Flask-Login</strong></h2>
<p>The most important part of Flask-Login is the <code>LoginManager</code> class that lets your application and Flask-Login work together.</p>
<p>In the <code>src/__init__.py</code> file, add the following code:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> decouple <span class="hljs-keyword">import</span> config
<span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> Flask
<span class="hljs-keyword">from</span> flask_login <span class="hljs-keyword">import</span> LoginManager <span class="hljs-comment"># Add this line</span>
<span class="hljs-keyword">from</span> flask_migrate <span class="hljs-keyword">import</span> Migrate
<span class="hljs-keyword">from</span> flask_sqlalchemy <span class="hljs-keyword">import</span> SQLAlchemy

app = Flask(__name__)
app.config.from_object(config(<span class="hljs-string">"APP_SETTINGS"</span>))

login_manager = LoginManager() <span class="hljs-comment"># Add this line</span>
login_manager.init_app(app) <span class="hljs-comment"># Add this line</span>
db = SQLAlchemy(app)
migrate = Migrate(app, db)

<span class="hljs-comment"># Registering blueprints</span>
<span class="hljs-keyword">from</span> src.accounts.views <span class="hljs-keyword">import</span> accounts_bp
<span class="hljs-keyword">from</span> src.core.views <span class="hljs-keyword">import</span> core_bp

app.register_blueprint(accounts_bp)
app.register_blueprint(core_bp)
</code></pre>
<p>In the above script, we created and initialized the login manager in our app.</p>
<p>Next, we need to provide a <code>user_loader</code> callback. This callback is used to reload the user object from the user ID stored in the session. It should take the ID of a user, and return the corresponding user object.</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> src.accounts.models <span class="hljs-keyword">import</span> User

<span class="hljs-meta">@login_manager.user_loader</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">load_user</span>(<span class="hljs-params">user_id</span>):</span>
    <span class="hljs-keyword">return</span> User.query.filter(User.id == int(user_id)).first()
</code></pre>
<p>The <code>User</code> model should implement the following properties and methods:</p>
<ul>
<li><code>is_authenticated</code>: This property returns True if the user is authenticated.</li>
<li><code>is_active</code>: This property returns True if this is an active user (the account is activated)</li>
<li><code>is_anonymous</code>: This property returns True if this is an anonymous user (actual users return False).</li>
<li><code>get_id()</code>: This method returns a string that uniquely identifies this user, and can be used to load the user from the <code>user_loader</code> callback.</li>
</ul>
<p>Now, we don't need to implement these explicitly. Instead, the Flask-Login provides a <code>UserMixin</code> class that contains the default implementations for all of these properties and methods. We just need to inherit it in the following way:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> datetime <span class="hljs-keyword">import</span> datetime

<span class="hljs-keyword">from</span> flask_login <span class="hljs-keyword">import</span> UserMixin <span class="hljs-comment"># Add this line</span>

<span class="hljs-keyword">from</span> src <span class="hljs-keyword">import</span> bcrypt, db


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span>(<span class="hljs-params">UserMixin, db.Model</span>):</span> <span class="hljs-comment"># Change this line</span>
    ....
</code></pre>
<p>We can also customize the default login process in the <code>src/__init__.py</code> file.</p>
<p>The name of the login view can be set as <code>LoginManager.login_view</code>. The value refers to the function name that will handle the login process.</p>
<pre><code class="lang-python">login_manager.login_view = <span class="hljs-string">"accounts.login"</span>
</code></pre>
<p>To customize the message category, set <code>LoginManager.login_message_category</code>:</p>
<pre><code class="lang-python">login_manager.login_message_category = <span class="hljs-string">"danger"</span>
</code></pre>
<h2 id="heading-how-to-add-templates-and-static-files"><strong>How to Add Templates and Static Files</strong></h2>
<p>Let's create a CSS file called <code>styles.css</code> inside the <code>src/static</code> folder:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.error</span> {
  <span class="hljs-attribute">color</span>: red;
  <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">5px</span>;
  <span class="hljs-attribute">text-align</span>: center;
}

<span class="hljs-selector-tag">a</span> {
  <span class="hljs-attribute">text-decoration</span>: none;
}
</code></pre>
<p>Let's also create the basic templates inside the <code>src/templates</code> folder. Create a <code>_base.html</code> file and add the following code:</p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"utf-8"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Two Factor Authentication<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- meta --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"description"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">""</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"author"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">""</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width,initial-scale=1"</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- styles --&gt;</span>
    <span class="hljs-comment">&lt;!-- CSS only --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css"</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">integrity</span>=<span class="hljs-string">"sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN"</span> <span class="hljs-attr">crossorigin</span>=<span class="hljs-string">"anonymous"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"{{url_for('static', filename="</span><span class="hljs-attr">styles.css</span>")}}"&gt;</span>
    {% block css %}{% endblock %}
  <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>

    {% include "navigation.html" %}

    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"container"</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span>

      <span class="hljs-comment">&lt;!-- messages --&gt;</span>
      {% with messages = get_flashed_messages(with_categories=true) %}
      {% if messages %}
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"row"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-md-4"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-md-4"</span>&gt;</span>
          {% for category, message in messages %}
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"alert alert-{{ category }} alert-dismissible fade show"</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"alert"</span>&gt;</span>
           {{message}}
           <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn-close"</span> <span class="hljs-attr">data-bs-dismiss</span>=<span class="hljs-string">"alert"</span> <span class="hljs-attr">aria-label</span>=<span class="hljs-string">"Close"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          {% endfor %}
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-md-4"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      {% endif %}
      {% endwith %}

      <span class="hljs-comment">&lt;!-- child template --&gt;</span>
      {% block content %}{% endblock %}

    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

    <span class="hljs-comment">&lt;!-- scripts --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://code.jquery.com/jquery-3.7.1.min.js"</span> <span class="hljs-attr">integrity</span>=<span class="hljs-string">"sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo="</span> <span class="hljs-attr">crossorigin</span>=<span class="hljs-string">"anonymous"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- JavaScript Bundle with Popper --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.8/dist/umd/popper.min.js"</span> <span class="hljs-attr">integrity</span>=<span class="hljs-string">"sha384-I7E8VVD/ismYTF4hNIPjVp/Zjvgyol6VFvRkX/vR+Vc4jQkC+hVqc2pM8ODewa9r"</span> <span class="hljs-attr">crossorigin</span>=<span class="hljs-string">"anonymous"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.min.js"</span> <span class="hljs-attr">integrity</span>=<span class="hljs-string">"sha384-BBtl+eGJRgqQAUMxJ7pMwbEyER4l1g+O15P+16Ep7Q9Q+zqX6gSbd85u4mG4QzX+"</span> <span class="hljs-attr">crossorigin</span>=<span class="hljs-string">"anonymous"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    {% block js %}{% endblock %}
  <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>The <code>_base.html</code> is the parent HTML file that will be inherited by the other templates. We have added Bootstrap 5 support in the above file. We are also making use of Flask Flashes to show Bootstrap alerts in the app.</p>
<p>Let's also create a <code>navigation.html</code> file that contains the navbar of the app:</p>
<pre><code class="lang-html"><span class="hljs-comment">&lt;!-- Navigation --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">nav</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"navbar bg-dark navbar-expand-lg bg-body-tertiary p-3"</span> <span class="hljs-attr">data-bs-theme</span>=<span class="hljs-string">"dark"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"container-fluid"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"navbar-brand"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"{{ url_for('core.home') }}"</span>&gt;</span>Two-Factor Authentication App<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"navbar-toggler"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span> <span class="hljs-attr">data-bs-toggle</span>=<span class="hljs-string">"collapse"</span> <span class="hljs-attr">data-bs-target</span>=<span class="hljs-string">"#navbarSupportedContent"</span> <span class="hljs-attr">aria-controls</span>=<span class="hljs-string">"navbarSupportedContent"</span> <span class="hljs-attr">aria-expanded</span>=<span class="hljs-string">"false"</span> <span class="hljs-attr">aria-label</span>=<span class="hljs-string">"Toggle navigation"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"navbar-toggler-icon"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"collapse navbar-collapse"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"navbarSupportedContent"</span>&gt;</span>
      {% if current_user.is_authenticated %}
      <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"{{ url_for('accounts.logout') }}"</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-danger me-2"</span>&gt;</span>Logout<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
      {% endif %}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">nav</span>&gt;</span>
</code></pre>
<p>Note that we have not yet created the views used above.</p>
<h2 id="heading-how-to-create-the-homepage"><strong>How to Create the Homepage</strong></h2>
<p>In this section, we'll first create a view function for the homepage inside the <code>core/views.py</code> file. Add the following code there:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> Blueprint, render_template
<span class="hljs-keyword">from</span> flask_login <span class="hljs-keyword">import</span> login_required

core_bp = Blueprint(<span class="hljs-string">"core"</span>, __name__)


<span class="hljs-meta">@core_bp.route("/")</span>
<span class="hljs-meta">@login_required</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">home</span>():</span>
    <span class="hljs-keyword">return</span> render_template(<span class="hljs-string">"core/index.html"</span>)
</code></pre>
<p>Notice that we have used the blueprint to add the route. We also added a <code>@login_required</code> middleware to prevent access for unauthenticated users.</p>
<p>Next, let's create an <code>index.html</code> file inside the <code>templates/core</code> folder, and add the following code:</p>
<pre><code class="lang-html">{% extends "_base.html" %}
{% block content %}

<span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-center"</span>&gt;</span>Welcome {{current_user.username}}!<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>

{% endblock %}
</code></pre>
<p>The HTML page will just have a welcome message for authenticated users.</p>
<p>Your file structure as of now should look like below:</p>
<pre><code class="lang-bash">flask-two-factor-auth/
├── src/
│   ├── accounts/
│   │   ├── __init__.py
│   │   └── views.py
│   ├── core/
│   │   ├── __init__.py
│   │   └── views.py
│   ├── static/
│   │   └── styles.css
│   ├── templates/
│   │   ├── core/
│   │   │   └── index.html
│   │   ├── _base.html
│   │   └── navigation.html
│   └── __init__.py
├── .env
├── config.py
└── manage.py
</code></pre>
<h2 id="heading-how-to-implement-user-registration"><strong>How to Implement User Registration</strong></h2>
<p>First of all, we'll create a registration form using Flask-WTF. Create a <code>forms.py</code> file inside the <code>accounts</code> package and add the following code:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> flask_wtf <span class="hljs-keyword">import</span> FlaskForm
<span class="hljs-keyword">from</span> wtforms <span class="hljs-keyword">import</span> EmailField, PasswordField
<span class="hljs-keyword">from</span> wtforms.validators <span class="hljs-keyword">import</span> DataRequired, Email, EqualTo, Length

<span class="hljs-keyword">from</span> src.accounts.models <span class="hljs-keyword">import</span> User


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">RegisterForm</span>(<span class="hljs-params">FlaskForm</span>):</span>
    username = StringField(
        <span class="hljs-string">"Username"</span>, validators=[DataRequired(), Length(min=<span class="hljs-number">6</span>, max=<span class="hljs-number">40</span>)]
    )
    password = PasswordField(
        <span class="hljs-string">"Password"</span>, validators=[DataRequired(), Length(min=<span class="hljs-number">6</span>, max=<span class="hljs-number">25</span>)]
    )
    confirm = PasswordField(
        <span class="hljs-string">"Repeat password"</span>,
        validators=[
            DataRequired(),
            EqualTo(<span class="hljs-string">"password"</span>, message=<span class="hljs-string">"Passwords must match."</span>),
        ],
    )

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">validate</span>(<span class="hljs-params">self, extra_validators</span>):</span>
        initial_validation = super(RegisterForm, self).validate(extra_validators)
        <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> initial_validation:
            <span class="hljs-keyword">return</span> <span class="hljs-literal">False</span>
        user = User.query.filter_by(username=self.username.data).first()
        <span class="hljs-keyword">if</span> user:
            self.username.errors.append(<span class="hljs-string">"Username already registered"</span>)
            <span class="hljs-keyword">return</span> <span class="hljs-literal">False</span>
        <span class="hljs-keyword">if</span> self.password.data != self.confirm.data:
            self.password.errors.append(<span class="hljs-string">"Passwords must match"</span>)
            <span class="hljs-keyword">return</span> <span class="hljs-literal">False</span>
        <span class="hljs-keyword">return</span> <span class="hljs-literal">True</span>
</code></pre>
<p>The <code>RegisterForm</code> extends the <code>FlaskForm</code> class and contains three fields – <code>username</code>, <code>password</code>, and <code>confirm</code>. We have added different validators such as <code>DataRequired</code>, <code>Length</code>, <code>Email</code>, and <code>EqualTo</code> to the respective fields.</p>
<p>We also defined a <code>validate()</code> method which is automatically called when the form is submitted.</p>
<p>Inside the method, we first perform the initial validation provided by FlaskForm. If that is successful, we perform our custom validation such as checking whether user is already registered, and matching the password with the confirmed password. If there are any errors, we append the error message in the respective fields.</p>
<p>Now, let's use this form inside the HTML file. Create an <code>accounts</code> directory inside the <code>templates</code> folder and add a new file called <code>register.html</code> inside it. Add the following code:</p>
<pre><code class="lang-html">{% extends "_base.html" %}

{% block content %}

<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"row"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-md-4"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-md-4"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">main</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-signin w-100 m-auto"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"form"</span> <span class="hljs-attr">method</span>=<span class="hljs-string">"post"</span> <span class="hljs-attr">action</span>=<span class="hljs-string">""</span>&gt;</span>
        {{ form.csrf_token }}
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"h3 mb-3 fw-normal text-center"</span>&gt;</span>Please register<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-floating"</span>&gt;</span>
          {{ form.username(placeholder="username", class="form-control mb-2") }}
          {{ form.username.label }}
            {% if form.username.errors %}
              {% for error in form.username.errors %}
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"alert alert-danger"</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"alert"</span>&gt;</span>
                  {{ error }}
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
              {% endfor %}
            {% endif %}
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-floating"</span>&gt;</span>
          {{ form.password(placeholder="password", class="form-control mb-2") }}
          {{ form.password.label }}
            {% if form.password.errors %}
              {% for error in form.password.errors %}
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"alert alert-danger"</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"alert"</span>&gt;</span>
                  {{ error }}
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
              {% endfor %}
            {% endif %}
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-floating"</span>&gt;</span>
          {{ form.confirm(placeholder="Confirm Password", class="form-control mb-2") }}
          {{ form.confirm.label }}
            {% if form.confirm.errors %}
              {% for error in form.confirm.errors %}
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"alert alert-danger"</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"alert"</span>&gt;</span>
                  {{ error }}
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
              {% endfor %}
            {% endif %}
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"w-100 btn btn-lg btn-primary"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>&gt;</span>Sign up<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-center mt-3"</span>&gt;</span>Already registered? <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"{{ url_for('accounts.login') }}"</span>&gt;</span>Login now<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-md-4"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

{% endblock %}
</code></pre>
<p>In the above Jinja template, we make use of the form that we created, and add relevant error handling logic checks for validation errors in each field. Users can submit the form by clicking the "Sign up" button, and a link below the form allows already registered users to navigate to the login page for authentication.</p>
<p>Next, let's use this form in the <code>views.py</code> to create a function to handle the registration process.</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> .forms <span class="hljs-keyword">import</span> RegisterForm
<span class="hljs-keyword">from</span> src.accounts.models <span class="hljs-keyword">import</span> User
<span class="hljs-keyword">from</span> src <span class="hljs-keyword">import</span> db, bcrypt
<span class="hljs-keyword">from</span> flask_login <span class="hljs-keyword">import</span> current_user
<span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> Blueprint, flash, redirect, render_template, request, url_for

accounts_bp = Blueprint(<span class="hljs-string">"accounts"</span>, __name__)

HOME_URL = <span class="hljs-string">"core.home"</span>
SETUP_2FA_URL = <span class="hljs-string">"accounts.setup_two_factor_auth"</span>
VERIFY_2FA_URL = <span class="hljs-string">"accounts.verify_two_factor_auth"</span>

<span class="hljs-meta">@accounts_bp.route("/register", methods=["GET", "POST"])</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">register</span>():</span>
    <span class="hljs-keyword">if</span> current_user.is_authenticated:
        <span class="hljs-keyword">if</span> current_user.is_two_factor_authentication_enabled:
            flash(<span class="hljs-string">"You are already registered."</span>, <span class="hljs-string">"info"</span>)
            <span class="hljs-keyword">return</span> redirect(url_for(HOME_URL))
        <span class="hljs-keyword">else</span>:
            flash(<span class="hljs-string">"You have not enabled 2-Factor Authentication. Please enable first to login."</span>, <span class="hljs-string">"info"</span>)
            <span class="hljs-keyword">return</span> redirect(url_for(SETUP_2FA_URL))
    form = RegisterForm(request.form)
    <span class="hljs-keyword">if</span> form.validate_on_submit():
        <span class="hljs-keyword">try</span>:
            user = User(username=form.username.data, password=form.password.data)
            db.session.add(user)
            db.session.commit()

            login_user(user)
            flash(<span class="hljs-string">"You are registered. You have to enable 2-Factor Authentication first to login."</span>, <span class="hljs-string">"success"</span>)

            <span class="hljs-keyword">return</span> redirect(url_for(SETUP_2FA_URL))
        <span class="hljs-keyword">except</span> Exception:
            db.session.rollback()
            flash(<span class="hljs-string">"Registration failed. Please try again."</span>, <span class="hljs-string">"danger"</span>)

    <span class="hljs-keyword">return</span> render_template(<span class="hljs-string">"accounts/register.html"</span>, form=form)
</code></pre>
<p>The route begins by checking if the current user is already authenticated. If so, it verifies whether 2FA is enabled for the user. If 2FA is already enabled, a message informs the user that they're already registered, redirecting them to the home URL. However, if the user is authenticated but 2FA is not enabled, a flash message prompts the user to enable 2FA first before logging in, redirecting them to the 2FA setup URL.</p>
<p>If the user is not authenticated or has not yet registered 2FA, the code initializes a registration form and proceeds to validate the form data on submission. Upon successful form validation, we create a new <code>User</code> object with the provided username and password and save it to the database.</p>
<p>Upon successful user registration, the newly registered user is logged in. A success message flashes, notifying the user of successful registration and prompting them to enable 2FA before logging in. Subsequently, the user is redirected to the 2FA setup URL to enable 2FA.</p>
<h2 id="heading-how-to-implement-user-login"><strong>How to Implement User Login</strong></h2>
<p>First, let's create a login form in the <code>accounts/forms.py</code> file:</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">LoginForm</span>(<span class="hljs-params">FlaskForm</span>):</span>
    username = StringField(<span class="hljs-string">"Username"</span>, validators=[DataRequired()])
    password = PasswordField(<span class="hljs-string">"Password"</span>, validators=[DataRequired()])
</code></pre>
<p>The form is similar to the registration form but it has only two fields – <code>username</code> and <code>password</code>.</p>
<p>Now, let's use this form inside new HTML file called <code>login.html</code> created inside the <code>templates/accounts</code> directory. Add the following code:</p>
<pre><code class="lang-html">{% extends "_base.html" %}

{% block content %}

<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"row"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-md-4"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-md-4"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">main</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-signin w-100 m-auto"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"form"</span> <span class="hljs-attr">method</span>=<span class="hljs-string">"post"</span> <span class="hljs-attr">action</span>=<span class="hljs-string">""</span>&gt;</span>
        {{ form.csrf_token }}
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"h3 mb-3 fw-normal text-center"</span>&gt;</span>Please sign in<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-floating"</span>&gt;</span>
          {{ form.username(placeholder="username", class="form-control mb-2") }}
          {{ form.username.label }}
            {% if form.username.errors %}
              {% for error in form.username.errors %}
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"alert alert-danger"</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"alert"</span>&gt;</span>
                {{ error }}
              <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
              {% endfor %}
            {% endif %}
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-floating"</span>&gt;</span>
          {{ form.password(placeholder="password", class="form-control mb-2") }}
          {{ form.password.label }}
            {% if form.password.errors %}
              {% for error in form.password.errors %}
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"alert alert-danger"</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"alert"</span>&gt;</span>
                  {{ error }}
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
              {% endfor %}
            {% endif %}
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"w-100 btn btn-lg btn-primary"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>&gt;</span>Sign in<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-center mt-3"</span>&gt;</span>New User? <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"{{ url_for('accounts.register') }}"</span>&gt;</span>Register now<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-md-4"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

{% endblock %}
</code></pre>
<p>The above HTML file is also similar to the <code>register.html</code> file but with just two fields for the username and password.</p>
<p>Next, let's create a view function to handle the login process inside the <code>accounts/views.py</code> file:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> .forms <span class="hljs-keyword">import</span> LoginForm, RegisterForm

<span class="hljs-meta">@accounts_bp.route("/login", methods=["GET", "POST"])</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">login</span>():</span>
    <span class="hljs-keyword">if</span> current_user.is_authenticated:
        <span class="hljs-keyword">if</span> current_user.is_two_factor_authentication_enabled:
            flash(<span class="hljs-string">"You are already logged in."</span>, <span class="hljs-string">"info"</span>)
            <span class="hljs-keyword">return</span> redirect(url_for(HOME_URL))
        <span class="hljs-keyword">else</span>:
            flash(<span class="hljs-string">"You have not enabled 2-Factor Authentication. Please enable first to login."</span>, <span class="hljs-string">"info"</span>)
            <span class="hljs-keyword">return</span> redirect(url_for(SETUP_2FA_URL))

    form = LoginForm(request.form)
    <span class="hljs-keyword">if</span> form.validate_on_submit():
        user = User.query.filter_by(username=form.username.data).first()
        <span class="hljs-keyword">if</span> user <span class="hljs-keyword">and</span> bcrypt.check_password_hash(user.password, request.form[<span class="hljs-string">"password"</span>]):
            login_user(user)
            <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> current_user.is_two_factor_authentication_enabled:
                flash(
                    <span class="hljs-string">"You have not enabled 2-Factor Authentication. Please enable first to login."</span>, <span class="hljs-string">"info"</span>)
                <span class="hljs-keyword">return</span> redirect(url_for(SETUP_2FA_URL))
            <span class="hljs-keyword">return</span> redirect(url_for(VERIFY_2FA_URL))
        <span class="hljs-keyword">elif</span> <span class="hljs-keyword">not</span> user:
            flash(<span class="hljs-string">"You are not registered. Please register."</span>, <span class="hljs-string">"danger"</span>)
        <span class="hljs-keyword">else</span>:
            flash(<span class="hljs-string">"Invalid username and/or password."</span>, <span class="hljs-string">"danger"</span>)
    <span class="hljs-keyword">return</span> render_template(<span class="hljs-string">"accounts/login.html"</span>, form=form)
</code></pre>
<p>The route starts by checking if the current user is already authenticated. If the user is authenticated and 2FA is enabled, a message informs the user they're already logged in, redirecting them to the home URL. If the user is authenticated but 2FA isn't enabled, a flash message prompts the user to enable 2FA before logging in, redirecting them to the 2FA setup URL.</p>
<p>If the user isn't authenticated, the code initializes a login form and validates the form data upon submission. Upon successful validation, it queries the database to find a user matching the provided username. If the user exists and the password matches the hashed password stored in the database, the user is logged in.</p>
<p>Additionally, if 2FA isn't enabled for the current user after successful login, a flash message prompts the user to enable 2FA before proceeding, redirecting them to the 2FA setup URL. If the login is successful and 2FA is enabled, the user is redirected to the 2FA verification URL.</p>
<p>If the user isn't registered, a flash message informs them to register. If there's a mismatch in the provided username or password, another flash message notifies the user of invalid credentials.</p>
<h2 id="heading-how-to-log-out-the-users">How to Log Out the Users</h2>
<p>Logging out the user is a very simple process. You just need to create a view function for it inside the <code>accounts/views.py</code> file:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> flask_login <span class="hljs-keyword">import</span> login_required, login_user, logout_user


<span class="hljs-meta">@accounts_bp.route("/logout")</span>
<span class="hljs-meta">@login_required</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">logout</span>():</span>
    logout_user()
    flash(<span class="hljs-string">"You were logged out."</span>, <span class="hljs-string">"success"</span>)
    <span class="hljs-keyword">return</span> redirect(url_for(<span class="hljs-string">"accounts.login"</span>))
</code></pre>
<p>The <code>Flask-Login</code> library contains a <code>logout_user</code> method that removes the user from the session. We used the <code>@login_required</code> decorator so that only authenticated users can logout.</p>
<h2 id="heading-how-to-add-the-setup-2fa-page">How to Add the Setup 2FA Page</h2>
<p>Up until now, we have been redirecting the users to the setup 2FA page whenever the 2FA is not enabled in their accounts, but we haven't implemented it yet. Let's do that in this section.</p>
<p>Let's start with the route for the page:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> src.utils <span class="hljs-keyword">import</span> get_b64encoded_qr_image

<span class="hljs-meta">@accounts_bp.route("/setup-2fa")</span>
<span class="hljs-meta">@login_required</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">setup_two_factor_auth</span>():</span>
    secret = current_user.secret_token
    uri = current_user.get_authentication_setup_uri()
    base64_qr_image = get_b64encoded_qr_image(uri)
    <span class="hljs-keyword">return</span> render_template(<span class="hljs-string">"accounts/setup-2fa.html"</span>, secret=secret, qr_image=base64_qr_image)
</code></pre>
<p>The route, created inside <code>accounts/views.py</code>, ensures that only authenticated users can access it using the <code>@login_required</code> decorator. </p>
<p>Upon accessing this route, the function retrieves the current user's <code>secret_token</code> for 2FA setup and generates a URI through <code>current_user.get_authentication_setup_uri()</code> to configure an authenticator app like Google Authenticator. </p>
<p>It also uses <code>get_b64encoded_qr_image(uri)</code> to obtain a Base64-encoded QR code image representing this setup URI. We will define it below. </p>
<p>Finally, it renders the <code>setup-2fa.html</code> template, passing the user's <code>secret_token</code> and the Base64-encoded QR image to the template for users to scan it.</p>
<p>Next, create a <code>utils.py</code> file in the <code>src</code> directory and add the following code to <a target="_blank" href="https://blog.ashutoshkrris.in/5-quick-python-projects#heading-qr-codes-in-python">generate the QR</a>:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> io <span class="hljs-keyword">import</span> BytesIO
<span class="hljs-keyword">import</span> qrcode
<span class="hljs-keyword">from</span> base64 <span class="hljs-keyword">import</span> b64encode


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_b64encoded_qr_image</span>(<span class="hljs-params">data</span>):</span>
    print(data)
    qr = qrcode.QRCode(version=<span class="hljs-number">1</span>, box_size=<span class="hljs-number">10</span>, border=<span class="hljs-number">5</span>)
    qr.add_data(data)
    qr.make(fit=<span class="hljs-literal">True</span>)
    img = qr.make_image(fill_color=<span class="hljs-string">'black'</span>, back_color=<span class="hljs-string">'white'</span>)
    buffered = BytesIO()
    img.save(buffered)
    <span class="hljs-keyword">return</span> b64encode(buffered.getvalue()).decode(<span class="hljs-string">"utf-8"</span>)
</code></pre>
<p>Remember the <code>qrcode</code> library we installed in the beginning of the tutorial? This is where we're going to use it. </p>
<p>Upon receiving <code>data</code> as input, representing the content to be embedded within the QR code, the function initializes a QRCode object using the <code>qrcode</code> library. It adds the provided data to this QR code instance and generates the QR code. The code then converts this QR code into an image representation. </p>
<p>Using a BytesIO object, it stores this image in memory. The function proceeds to encode the content of this in-memory buffer, representing the QR code image, into Base64 format. Finally, it returns this Base64-encoded string, encapsulating the QR code image, ready for transmission or display in various applications.</p>
<p>Next, let's create the <code>setup-2fa.html</code> page inside the <code>templates/accounts</code> folder, and add the following content:</p>
<pre><code class="lang-html">{% extends "_base.html" %}

{% block content %}

<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"row"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-md-4"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-md-4"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">main</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-signin w-100 m-auto"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"form"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h5</span>&gt;</span>Instructions!<span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>Download <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2&amp;hl=en&amp;gl=US"</span> <span class="hljs-attr">target</span>=<span class="hljs-string">"_blank"</span>&gt;</span>Google Authenticator<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span> on your mobile.<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>Set up a new authenticator.<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>Once you have scanned the QR, please click <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"{{ url_for('accounts.verify_two_factor_auth') }}"</span>&gt;</span>here.<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-center"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"data:image/png;base64, {{ qr_image }}"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"Secret Token"</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"width:200px;height:200px"</span>/&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-group"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"secret"</span>&gt;</span>Secret Token<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-control"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"secret"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"{{ secret }}"</span> <span class="hljs-attr">readonly</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-center mt-2"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-primary"</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">"copySecret()"</span>&gt;</span>
            Copy Secret
          <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"mt-4 text-center"</span>&gt;</span>
          Once you have scanned the QR, please click <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"{{ url_for('accounts.verify_two_factor_auth') }}"</span>&gt;</span>here<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>.
        <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-md-4"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

{% endblock %}

{% block js %}
<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">copySecret</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">var</span> copyText = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"secret"</span>);
    copyText.select();
    copyText.setSelectionRange(<span class="hljs-number">0</span>, <span class="hljs-number">99999</span>); <span class="hljs-comment">/*For mobile devices*/</span>
    <span class="hljs-built_in">document</span>.execCommand(<span class="hljs-string">"copy"</span>);
    alert(<span class="hljs-string">"Successfully copied TOTP secret token!"</span>);
  }
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
{% endblock %}
</code></pre>
<p>We add some instructions in the page for the users to follow. These instructions provide clear steps for users to enable 2FA: directing them to download the Google Authenticator app via a link, guiding the setup process within the app, and prompting users to proceed by clicking a link after scanning the displayed QR code.</p>
<p>Displaying the QR code is central to the setup process. The template embeds the QR code image using an <code>&lt;img&gt;</code> tag with its source set to a Base64-encoded string (<code>{{ qr_image }}</code>). This image represents the secret key essential for 2FA setup. </p>
<p>We also show the secret key in read-only mode, allowing users to view the key without being able to modify it. We have added a copy button to make it easier for the users to copy the key.</p>
<p>Moreover, we have added a link to the 2FA verification page guiding users to proceed with the setup process after scanning the QR code. We will implement this functionality in the next section.</p>
<p>Here's how your page looks right now:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/11/Screenshot-2023-11-26-010925.png" alt="Image" width="600" height="400" loading="lazy">
<em>2FA Setup Page</em></p>
<h2 id="heading-how-to-add-a-2fa-verification-page">How to Add a 2FA Verification Page</h2>
<p>In this section, let's implement the 2FA verification. To start with, we will require an OTP form where users can enter their OTP. Add the following content in the <code>accounts/forms.py</code> file:</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TwoFactorForm</span>(<span class="hljs-params">FlaskForm</span>):</span>
    otp = StringField(<span class="hljs-string">'Enter OTP'</span>, validators=[
                      InputRequired(), Length(min=<span class="hljs-number">6</span>, max=<span class="hljs-number">6</span>)])
</code></pre>
<p>The <code>TwoFactorForm</code> contains just one field (<code>otp</code>) to get the OTP from the users.</p>
<p>Now, let's use this form in the <code>verify-2fa.html</code> file inside the <code>templates/accounts</code> folder:</p>
<pre><code class="lang-html">{% extends "_base.html" %}

{% block content %}

<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"row"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-md-4"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-md-4"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">main</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-signin w-100 m-auto"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"form"</span> <span class="hljs-attr">method</span>=<span class="hljs-string">"post"</span> <span class="hljs-attr">action</span>=<span class="hljs-string">""</span>&gt;</span>
        {{ form.csrf_token }}
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"h3 mb-3 fw-normal text-center"</span>&gt;</span>Enter OTP<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-floating"</span>&gt;</span>
          {{ form.otp(placeholder="OTP", class="form-control mb-2") }}
          {{ form.otp.label }}
            {% if form.otp.errors %}
              {% for error in form.otp.errors %}
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"alert alert-danger"</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"alert"</span>&gt;</span>
                {{ error }}
              <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
              {% endfor %}
            {% endif %}
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"w-100 btn btn-lg btn-primary"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>&gt;</span>Verify<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-md-4"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

{% endblock %}
</code></pre>
<p>The Jinja template essentially contains a form with one field for OTP and a verify button. </p>
<p>Let's create the route which handles the submission of this form inside the <code>accounts/views.py</code> file:</p>
<pre><code class="lang-python"><span class="hljs-meta">@accounts_bp.route("/verify-2fa", methods=["GET", "POST"])</span>
<span class="hljs-meta">@login_required</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">verify_two_factor_auth</span>():</span>
    form = TwoFactorForm(request.form)
    <span class="hljs-keyword">if</span> form.validate_on_submit():
        <span class="hljs-keyword">if</span> current_user.is_otp_valid(form.otp.data):
            <span class="hljs-keyword">if</span> current_user.is_two_factor_authentication_enabled:
                flash(<span class="hljs-string">"2FA verification successful. You are logged in!"</span>, <span class="hljs-string">"success"</span>)
                <span class="hljs-keyword">return</span> redirect(url_for(HOME_URL))
            <span class="hljs-keyword">else</span>:
                <span class="hljs-keyword">try</span>:
                    current_user.is_two_factor_authentication_enabled = <span class="hljs-literal">True</span>
                    db.session.commit()
                    flash(<span class="hljs-string">"2FA setup successful. You are logged in!"</span>, <span class="hljs-string">"success"</span>)
                    <span class="hljs-keyword">return</span> redirect(url_for(HOME_URL))
                <span class="hljs-keyword">except</span> Exception:
                    db.session.rollback()
                    flash(<span class="hljs-string">"2FA setup failed. Please try again."</span>, <span class="hljs-string">"danger"</span>)
                    <span class="hljs-keyword">return</span> redirect(url_for(VERIFY_2FA_URL))
        <span class="hljs-keyword">else</span>:
            flash(<span class="hljs-string">"Invalid OTP. Please try again."</span>, <span class="hljs-string">"danger"</span>)
            <span class="hljs-keyword">return</span> redirect(url_for(VERIFY_2FA_URL))
    <span class="hljs-keyword">else</span>:
        <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> current_user.is_two_factor_authentication_enabled:
            flash(
                <span class="hljs-string">"You have not enabled 2-Factor Authentication. Please enable it first."</span>, <span class="hljs-string">"info"</span>)
        <span class="hljs-keyword">return</span> render_template(<span class="hljs-string">"accounts/verify-2fa.html"</span>, form=form)
</code></pre>
<p>The route starts by initializing a form (<code>TwoFactorForm</code>) meant for 2FA verification using the data obtained from the request. Upon form submission, the code proceeds with several conditional checks to validate the OTP entered by the user.</p>
<p>Once the form has been successfully submitted and validated, the code verifies the authenticity of the OTP using <code>current_user.is_otp_valid(form.otp.data)</code>, which checks if the entered OTP is valid for the current user. If the OTP is valid, the code executes the following logic:</p>
<ul>
<li>If the provided OTP is valid and 2FA is already enabled for the user, a success message is flashed indicating successful 2FA verification, and the user is redirected to the home URL.</li>
<li>If the OTP is valid but 2FA isn't enabled for the user, it attempts to enable 2FA for that user. Upon successful activation, a success message flashes, and the user is redirected to the home URL.</li>
</ul>
<p>Furthermore, if the OTP entered by the user is invalid, the code flashes an error message indicating an invalid OTP and redirects the user back to the 2FA verification URL to retry the verification process.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/11/Screenshot-2023-11-26-011107.png" alt="Image" width="600" height="400" loading="lazy">
<em>2FA Verification Page</em></p>
<p>With this, we have completed the implementation of all the features! 🎉</p>
<h2 id="heading-how-to-run-the-completed-app-for-the-first-time"><strong>How to Run the Completed App for the First Time</strong></h2>
<p>Now that our application is ready, you can first migrate the database, and then run the app.</p>
<p>To initialize the database (create a migration repository), use the command:</p>
<pre><code class="lang-bash">flask db init
</code></pre>
<p>To migrate the database changes, use the command:</p>
<pre><code class="lang-bash">flask db migrate
</code></pre>
<p>To apply the migrations, use the command:</p>
<pre><code class="lang-bash">flask db upgrade
</code></pre>
<p>Since this is the first time we're running our app, you'll need to run all the above commands. Later, whenever you make changes to the database, you'll just need to run the last two commands.</p>
<p>After that, you can run your application using the command:</p>
<pre><code>python manage.py run
</code></pre><p>Since we have completed the development, here's how your file structure should look like:</p>
<pre><code class="lang-bash">flask-two-factor-auth/
├── migrations/
├── src/
│   ├── accounts/
│   │   ├── __init__.py
│   │   ├── forms.py
│   │   ├── models.py
│   │   └── views.py
│   ├── core/
│   │   ├── __init__.py
│   │   └── views.py
│   ├── static/
│   │   └── styles.css
│   ├── templates/
│   │   ├── accounts/
│   │   │   ├── login.html
│   │   │   ├── register.html
│   │   │   ├── setup-2fa.html
│   │   │   └── verify-2fa.html
│   │   ├── core/
│   │   │   └── index.html
│   │   ├── _base.html
│   │   └── navigation.html
│   ├── __init__.py
│   └── utils.py
├── .env
├── config.py
└── manage.py
</code></pre>
<h2 id="heading-wrapping-up"><strong>Wrapping up</strong></h2>
<p>In this tutorial, you learned how to set up two-factor authentication in your Flask app using PyOTP.</p>
<p>Here's the link to the <a target="_blank" href="https://github.com/ashutoshkrris/Flask-Two-Factor-Authentication">GitHub repository</a>. Feel free to check it out whenever you're stuck.</p>
<p>Here are some other tutorials I wrote about authentication, email verification, and OTPs that you might enjoy:</p>
<ul>
<li><a target="_blank" href="https://blog.ashutoshkrris.in/how-to-set-up-basic-user-authentication-in-a-flask-app">How to Set Up Basic User Authentication in a Flask App</a></li>
<li><a target="_blank" href="https://www.freecodecamp.org/news/how-to-setup-user-authentication-in-flask/">How to Set Up Email Verification in a Flask App</a></li>
<li><a target="_blank" href="https://blog.ashutoshkrris.in/how-to-generate-otps-using-pyotp-in-python">How To Generate OTPs Using PyOTP in Python</a></li>
</ul>
<p>Thank you for reading. I hope you found this article useful. You can follow me on <a target="_blank" href="https://twitter.com/ashutoshkrris">Twitter</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Prevent Account Loss When using Two-Factor Authentication ]]>
                </title>
                <description>
                    <![CDATA[ If someone gains unauthorized access to your passwords, two-factor authentication (2FA) can prevent them from accessing your account.  But if you ever lose access to all your 2FA methods, you have lost your account. How do you prevent such loss? In t... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-prevent-account-loss-when-using-two-factor-authentication/</link>
                <guid isPermaLink="false">66b9ff4f7a31f91cb02e2f70</guid>
                
                    <category>
                        <![CDATA[ Security ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Two-factor authentication ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Obum ]]>
                </dc:creator>
                <pubDate>Wed, 22 Mar 2023 16:28:07 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/03/pexels-karolina-grabowska-4467737.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>If someone gains unauthorized access to your passwords, two-factor authentication (2FA) can prevent them from accessing your account. </p>
<p>But if you ever lose access to all your 2FA methods, you have lost your account. How do you prevent such loss?</p>
<p>In this article, we will look at two-factor authentication (2FA), its methods, and how to prevent account loss because of using it.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><a class="post-section-overview" href="#heading-what-is-two-factor-authentication-2fa">What is Two-Factor Authentication (2FA)</a>?</li>
<li><a class="post-section-overview" href="#heading-methods-of-two-factor-authentication">Methods of Two-Factor Authentication</a></li>
<li><a class="post-section-overview" href="#heading-the-problem-with-two-factor-authentication">The problem with Two-Factor Authentication</a></li>
<li><a class="post-section-overview" href="#heading-how-to-protect-yourself-from-losing-access-to-your-accounts">How to Protect Yourself from Losing Access to Your Accounts</a>  </li>
<li><a class="post-section-overview" href="#heading-1-backup-and-write-down-the-recovery-codes">Backup and write down the recovery code(s)</a>  </li>
<li><a class="post-section-overview" href="#heading-2-backup-and-write-down-the-authenticator-app-seed">Backup and write down the authenticator app seed</a>  </li>
<li><a class="post-section-overview" href="#heading-3-set-up-more-than-one-2fa-method">Set up more than one 2FA method</a>  </li>
<li><a class="post-section-overview" href="#heading-4-always-update-2fa-methods">Always update 2FA methods</a>  </li>
<li><a class="post-section-overview" href="#heading-5-set-up-recovery-email-and-phone">Set up recovery email and phone</a> </li>
<li><a class="post-section-overview" href="#heading-summary">Summary</a></li>
</ul>
<h2 id="heading-what-is-two-factor-authentication-2fa">What is Two-Factor Authentication (2FA)?</h2>
<p>Two-Factor Authentication is an extra security setting for your account that many platforms have enabled. </p>
<p>It is an extra security setting because you already have some "first" way of authenticating yourself. This "first" way could be password sign-in or federated identity sign-in. Federated identity means signing in with another provider, like Apple, Facebook, Google, and so on.</p>
<p>Two-Factor authentication helps reduce unauthorized access to your data or account. It is a second sign-in step to verify that you are the owner of the account. So, in addition to your first sign-in method, you will have to complete this second step (hence two-factor) to access your account.</p>
<p>Two-Factor authentication is not about using and securing your passwords. That one is basic account security. We are talking about an advanced security step where, after entering your password, you still need to enter some code or complete some action before you gain access to your account. </p>
<p>In this article, platform means any place where you can sign in and sign out. freeCodeCamp, LinkedIn, and Twitter are examples of platforms. In this article, a platform is a place where you have an account.</p>
<p>Some platforms don't offer 2FA. You might have relatively little data with them. So 2FA would be overkill there. On the other hand, the major and mainstream platforms where you can have an account offer 2FA. These are platforms where a user's account is worth hacking. </p>
<p>In most platforms, 2FA is optional. In a few, however, you are required to set up 2FA from the very first time you access the account and you can't turn it off. In other words, 2FA is a must-do on a few platforms.</p>
<p>You should set up 2FA where it is available. To set up 2FA, go to the security settings of your account on a supporting platform. Set up 2FA using at least of one the specified methods and you are good to go. On subsequent sign-ins, you will need to complete 2FA to enter the account.</p>
<h2 id="heading-methods-of-two-factor-authentication">Methods of Two-Factor Authentication</h2>
<p>Methods of 2FA refer to the various ways to set up 2FA. They are as follows:</p>
<ol>
<li>Security Key 2FA</li>
<li>Phone number 2FA</li>
<li>Authenticator app 2FA</li>
<li>Sign-In prompt</li>
<li>Recovery code(s)</li>
</ol>
<p>Security keys are USB or Bluetooth keys that you can connect to your device. They are physical 2FA devices and seem to be the most secure. This is because it is highly unlikely that a hacker would come and steal the key from your house. </p>
<p>To set up 2FA using keys, plug in the key or connect via Bluetooth and complete the steps. You can then use the key in consequent sign-ins. You have to buy these keys from the market or online to use them. </p>
<p>Phone number 2FA involves receiving a One-Time Password (OTP) code either via call or SMS. Provide a phone number and the platform sends an OTP to it. Sometimes, you could receive an automated call with the code. Either way, enter the code in the platform and you have successfully set up the phone number 2FA. </p>
<p>On subsequent sign-ins to access your account, after entering your password, you will receive an OTP code to that phone. Enter the code to gain access to your account.</p>
<p>Authenticator apps generate a 6-digit code every minute. <a target="_blank" href="https://www.google.com/search?q=authenticator+apps">There are many authenticator apps</a>, like Google Authenticator, Microsoft Authenticator, and others. </p>
<p>To set up an authenticator app, you either scan a QR code or enter a seed phrase. The platform where your account resides will provide you with either of these. Scan or enter the phrase and you will keep getting a unique 6-digit code every minute. </p>
<p>In the next sign-ins, after entering your password, paste the latest 6-digit code from the authenticator app and you are in.</p>
<p>Sign-in prompts are not as common as other 2FA methods. Not all platforms have this feature. It involves authorizing your sign-in from an app or website of that platform where you are already signed in. </p>
<p>GitHub and Google have these features. With the GitHub app, you can complete 2FA by entering a number on the screen from the app/website you signed in to. Google does it together with your Android device and your Google account.</p>
<p>Aside from the above 2FA methods, we also have recovery codes. Recovery codes are a one-time-use code that you can use to complete 2FA. You can access them under the 2FA settings of your account.</p>
<p>In fact, once you set at least one 2FA method on your account, the platform autogenerates these recovery codes for you. These codes are like a backup option for 2FA. You are meant to use them when you don't have access to the other 2FA methods.</p>
<h2 id="heading-the-problem-with-two-factor-authentication">The Problem with Two-Factor Authentication</h2>
<p>The problem with 2FA is that if you lose access to all the methods you've set up, <strong>you've permanently lost access</strong> to that account. Let me explain.</p>
<p>2FA ensures that it is the correct user that is accessing an account. That's why we have those above secondary methods aside from your password. 2FA can only be enabled or disabled while signed in. </p>
<p>But aside from the recovery codes, there is no other recovery mechanism. If you lose the security keys, phone number, devices with the authenticator apps and previous sign-ins, and the recovery codes, your account is gone. Not even the account support for that platform can help you. </p>
<p>This is not the common "Forgot Password" feature, where the platform sends a unique link or code to your email or phone to reset your password. This is 2FA. Once you lose all 2FA methods you had set, your account is gone. Support can't give you the recovery codes because they don't know them. Those codes are encrypted with your account's access (only you can access them when you are signed in).</p>
<p>Does this mean that you shouldn't set up 2FA? </p>
<p>No. It means that in addition to setting up 2FA, you have to guard your 2FA methods. Remember that it is security that led us to 2FA. Well, 2FA itself also needs security. So you have to secure it.</p>
<p>From here, we will be looking at the various things you can do to prevent account loss due to Two-Factor Authentication.</p>
<h2 id="heading-how-to-protect-yourself-from-losing-access-to-your-accounts">How to Protect Yourself from Losing Access to Your Accounts</h2>
<h3 id="heading-1-backup-and-write-down-the-recovery-codes">1. Backup and write down the recovery code(s)</h3>
<p>All platforms that grant 2FA also give a recovery code(s). Always back them up. Copy and save the recovery codes securely somewhere of your choice. Hide them discretely online. Encrypt them in some vaulted storage. </p>
<p>Most importantly, <strong>write</strong> them down. Like use your hand and write with a pen in some diary or book you won't lose. You can equally print and store them with your documents and certificates. Just protect each recovery code per platform in the most secure way you're able.</p>
<p>Also, don't store the recovery code of an account in that same account. No one keeps spare keys inside the house. You give out your spare keys to trusted persons or keep them in other places where you can go retrieve them when need be. This is because if your main key goes missing while you are out, you can go and retrieve the spares. You can't retrieve the spare keys when they are inside the house and you are locked out.</p>
<p>In the same vein, it makes no sense to keep the recovery codes of your Google Account's 2FA inside your account's Google Drive or in a private Google Doc owned by the same account. When you will need it, you can't get it.</p>
<p>Recovery codes are <strong>one-time-use</strong> codes. You can't reuse the same recovery code for another 2FA session. You shouldn't really be using your recovery codes. If you start using them, it is a sign that you need to either update your 2FA methods, turn off 2FA temporarily, or regenerate a new set of recovery codes (to replace the used ones).</p>
<p>You can always copy out your recovery codes. Also, you can always generate a new set of recovery codes in each platform. Every platform permits that. Remember that you have to be signed in to do all these things. </p>
<p>Also, anytime you disable or turn off two-factor authentication in your account settings, the previous recovery codes become invalid. If you enable 2FA again, you will need to re-backup and re-write the new recovery codes.  </p>
<p>Make sure you store recovery code(s) for each platform in multiple and different places. </p>
<h3 id="heading-2-backup-and-write-down-the-authenticator-app-seed">2. Backup and write down the authenticator app seed</h3>
<p>When setting up the authenticator app 2FA, don't use the QR code option. Go for the seed option. The seed for authenticator apps comes as a series of about 20 to 40 alphanumeric characters. When the platform shows you this seed, first <strong>write</strong> it down. </p>
<p>Write down the authenticator app seed in your diary or in some book you've set aside for backup. If possible, copy it out and print it. Equally backup the seed for each platform in some other online media where you can retrieve it from. You want to minimize your chances of losing these seeds. </p>
<p>Each minute, authenticator apps generate 6-digit codes <strong>based on the seed</strong> and not based on the app itself or the platform. If you paste that same seed into another authenticator app, the two apps will be generating the exact same 6 digits, every minute. In fact, if you re-use that exact same phrase to recreate another 2FA entry in the same authenticator app, the two entries will be generating the same 6-digit code per minute.</p>
<p>This is why the authenticator app seed is as important as the 2FA recovery codes. If you lose access to the device that your 2FA authenticator app is on, you can put your seeds in another authenticator and get back the 6-digit codes for 2FA. Protect these seeds too. Because if someone has both your passwords and seeds, then they have access to your accounts.  </p>
<p>Backing up and writing down authenticator app seeds is necessary and it is under-preached. Many people don't realize that device loss means account loss if the authenticator app was their only 2FA method and if they didn't save the seed and recovery codes somewhere. </p>
<p>A device crash can happen. The Operating System might crash and you may lose apps and data. The authenticator app could be mistakenly uninstalled. Backing up and writing down the seeds prevent these circumstances from affecting your 2FA setups. </p>
<p>You can reinstall the authenticator app and reconfigure the entries of each account from your saved seed, without needing to go to the account settings of each platform. Also, you will be capable of continuing to use your two-factor authentication methods, without needing to re-backup or re-write down a new set of recovery codes.</p>
<p>If you've already set up the authenticator app 2FA, and you didn't save the original seed your account's platform gave you, please, please, please go and reconfigure the authenticator app 2FA in your security settings. You might have to just disable only the authenticator app and turn it back on. While re-enabling, make sure you back up and write down the seed. You don't want to live the experience of being locked out of your account.</p>
<h3 id="heading-3-set-up-more-than-one-2fa-method">3. Set up more than one 2FA method</h3>
<p>Setting up more than one method for two-factor authentication reduces your chances of account loss. The idea is to ensure that you always have access to at least one (if not all) 2FA methods. You can set up all the available 2FA methods per platform account. </p>
<p>For USB/Bluetooth security key, you can use the same key for all your accounts across various platforms. For your phone number, you can use the same phone number across each account on each platform. (But some platforms don't permit you to have multiple accounts with the same phone number. Have this in mind if you fall into that category).</p>
<p>The authenticator app seed for each account per platform is different. But you can use the same authenticator app for all accounts in which you've set up 2FA. Just remember to back up and write down the seeds as mentioned in the previous section.</p>
<p>So for each platform, you want to ensure that you have set more than one 2FA method. You can receive an SMS with some phone number. You have a working authenticator app. You've backed up and written down the authenticator app seed and 2FA recovery codes. And where you can, you've equally set up the USB/Bluetooth security key.</p>
<h3 id="heading-4-always-update-2fa-methods">4. Always update 2FA methods</h3>
<p>Things can happen that warrant updating your 2FA methods. Updating 2FA methods include removing or adding some methods. You can equally change the settings of the same method. </p>
<p>For example, let's say you never had a security key in your account. But you had set up 2FA with a phone number and authenticator app. Then you just bought a new security key. You can go and add the security key in your 2FA settings as a new method. On the other hand, if you lose your USB/Bluetooth security key, you can disable the security key option. Then when you buy a new one, you can put it back in your settings. </p>
<p>If you lost your all backups and written-down versions of your authenticator app seeds and 2FA recovery codes, you can regenerate new ones and re-backup and re-write down. You really shouldn't lose everything. Such loss is not good. Well, anything is possible. Prevention is the only remedy as there is no cure in the world for complete 2FA loss. </p>
<p>Also, it is okay to turn off 2FA if you need to. 2FA is recommended and necessary. But if you see the need to, turn it off for the moment. Then set it up back sometime later on. </p>
<h3 id="heading-5-set-up-recovery-email-and-phone">5. Set up recovery email and phone</h3>
<p>Backup email and phone are not really a 2FA thing. The reason is they are always there whether you configure two-factor or not. Most major platforms permit you to set a recovery email and or a recovery phone number for your account. These recovery assets come in handy when you forget your password and not when you lose 2FA.</p>
<p>Well, we are talking about security, so it is worth mentioning that you should have recovery email and phone properly set up where possible. </p>
<p>In some platforms, your account or your recovery phone number can be different from your 2FA phone number. Your 2FA phone number must always be one where you can receive an OTP (via call or SMS) and use it to complete the 2FA step.</p>
<h2 id="heading-summary">Summary</h2>
<p>You want to lock out malicious access to your account. But you don't want to lock out yourself.  </p>
<p>In this guide, we've looked at how to best use the two-factor authentication feature across various accounts. At the same time, we've also seen how you can ensure that you don't lose access to your account because you tried securing it in the first place.</p>
<p>Back up and write down recovery codes and authenticator app seeds. Set up multiple 2FA methods. Always review and update your 2FA settings. Do these and be rest assured of the best online security.</p>
<p>Cheers!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Secure User Authentication Methods – 2FA, Biometric, and Passwordless Login Explained ]]>
                </title>
                <description>
                    <![CDATA[ In today's digital world, user authentication is essential in ensuring secure access to online accounts and resources.  With the rise of cyber-threats, companies need to ensure that their users are authenticated before accessing any sensitive informa... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/user-authentication-methods-explained/</link>
                <guid isPermaLink="false">66b8dc06d3be22cd680b3b84</guid>
                
                    <category>
                        <![CDATA[ Application Security ]]>
                    </category>
                
                    <category>
                        <![CDATA[ authentication ]]>
                    </category>
                
                    <category>
                        <![CDATA[ biometric authentication ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Two-factor authentication ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Hillary Nyakundi ]]>
                </dc:creator>
                <pubDate>Tue, 17 Jan 2023 18:05:56 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/01/OOP.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In today's digital world, user authentication is essential in ensuring secure access to online accounts and resources. </p>
<p>With the rise of cyber-threats, companies need to ensure that their users are authenticated before accessing any sensitive information. This helps protect the online safety of both parties.</p>
<p>In the past, the most common authentication method that we're all likely familiar with was using a username and password to sign in to apps and services. </p>
<p>And if you're a programmer, you've likely developed projects where you have implemented this method as a form of authentication.</p>
<p>But hey! Guess what? Things have changed over the past couple of years. With advancements in technology, this means security has to be taken more seriously and we need more strict authentication approaches.</p>
<p>And that's what we'll learn about in this tutorial.</p>
<h2 id="heading-different-authentication-methods">Different Authentication Methods</h2>
<p>There are many different methods of authenticating users, and each has its own advantages and disadvantages. The most common methods of user authentication are:</p>
<ul>
<li>username and password,</li>
<li>two-factor authentication,</li>
<li>biometrics</li>
</ul>
<p>just to list a few.</p>
<p>But as time passes, we continue to evolve and new methods are introduced that provide a safer way to store user data. Some examples of these methods include:</p>
<ul>
<li>Passwordless login</li>
<li>Multi-factor authentication, and</li>
<li>Token-based authentication</li>
</ul>
<p>In this article, we will explore the most common methods of user authentication. By understanding the different options available, you can choose the best method for your needs. </p>
<p>But first, let's understand what we mean by authentication.</p>
<h2 id="heading-what-is-user-authentication">What is User Authentication?</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/e79vtruyjlui8cz8j8r6-1.png" alt="e79vtruyjlui8cz8j8r6-1" width="600" height="400" loading="lazy"></p>
<p>To better understand what authentication is all about, we can relate it to a real world example. </p>
<p>Let's take a scenario where you are out at the store shopping and you need to make a payment with your credit card. You go through the steps of swiping your card to authenticate the payment, but what really happens before the transaction is complete?</p>
<p>After swiping your card, the machine will read the card info and send it to the issuer for verification. The issuer will then check for a couple of things in order to verify the transaction. </p>
<p>In this case, the issuer will check the card info against what is on record, like expiry date, card number, and account balance. If everything matches what is on record and there are sufficient funds, an authorization message is sent and the transaction is allowed. </p>
<p>In a case where the info doesn't match and/or there are not enough funds, a decline message is instead sent and the transaction is declined.</p>
<p>Now with this understanding, authentication is the process of verifying the identity of a user. User authentication verifies the identity of a user before granting access to sensitive information or systems. </p>
<h3 id="heading-what-are-some-common-authentication-methods">What are some common authentication methods?</h3>
<p>There are many ways to authenticate a user, and each platform has different methods that they use. But as I mentioned above, some common methods include username and password, fingerprint, facial recognition, and iris scan.</p>
<h4 id="heading-usernamepassword-authentication">Username/password authentication</h4>
<p>Username and password are the most common form of authentication. This is where a user enters their username and password into a login form, and if the credentials match what is stored in the database, the user is granted access. </p>
<p>But keep in mind that this method can be insecure if passwords are not properly encrypted or if users reuse the same password for multiple accounts.</p>
<h4 id="heading-biometric-authentication-methods">Biometric authentication methods</h4>
<p>Fingerprint authentication uses an individual's unique fingerprint to verify their identity. This can be done using a fingerprint scanner or by using a smartphone's built-in sensor. </p>
<p>This method is most commonly used in smart phones and recently there has been an increase in the use of this method in laptops, too.</p>
<p>Facial recognition works in a similar way, using an image of the user's face to verify their identity. Iris scanning is another biometric authentication method that uses an image of the user's iris to identify them.</p>
<h2 id="heading-more-secure-authentication-methods">More Secure Authentication Methods</h2>
<p>Even though these have historically been the most common methods, recently we have seen a rise in other methods which are said to be more secure. </p>
<p>In fact, many organizations are turning to these techniques in addition to the user providing a username and password. This is considered an extra layer of security.</p>
<p>These newer techniques include: </p>
<h3 id="heading-1-two-factor-authentication">1. Two-Factor Authentication</h3>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/hktn8ib7inl9whmybqp2.jpg" alt="Two-Factor Authentication" width="600" height="400" loading="lazy"></p>
<p>Two-factor authentication, also known as 2FA, is an additional layer of security that can be used to protect your account. </p>
<p>2FA is a way of verifying a user from two different approaches, thats is: using something the user already knows (like their username and password), and using something the user has, like a phone.</p>
<p>When 2FA is enabled, apart from entering the username and password correctly, you will be prompted for the second piece of information (usually a code generated by an app on your phone or a code sent via SMS). This makes it much more difficult for someone to gain access to your account, even if they have your password.</p>
<p>2FA is not foolproof, but it is more secure compared to using only username and password. This makes it a valuable tool to help keep your account safe. If you are concerned about the security of your account, enabling 2FA will be of great help.</p>
<h3 id="heading-2-passwordless-login">2. Passwordless Login</h3>
<p>Passwordless login, just as the name suggests, is a method of logging into an account without needing a username or a password. There are many reasons why you might want to stop using a password and opt for a passwordless login experience.</p>
<p>For one, it's more convenient for users. They don't have to remember yet another username and password combination. And two, it's more secure. There are no weak passwords to be guessed or brute-forced by attackers.</p>
<p>So how do you set up a passwordless login? There are a few different methods you can use, each with its own set of pros and cons.</p>
<h4 id="heading-different-methods-of-passwordless-login">Different methods of passwordless login</h4>
<p>One popular method is to use an email link. When the user wants to log in, they provide their email address. They then receive an email with a link that expires after a certain amount of time. When they click the link, they're logged in without having to enter a password.</p>
<p>Another option is to use a one-time code generated by an app on the user's phone. The code is valid for only a short period of time, so even if someone were to intercept it, they wouldn't be able to use it.</p>
<p>Which method is best for you depends on your security needs and preferences. But whatever you choose, ditching the password is sure to make life easier for your users - and make your site more secure in the process.</p>
<p>For a practical guide on how to use the passwordless method, <a target="_blank" href="https://youtu.be/0OYA1c3bjgM">Auth0</a> has a step-by-step video guide on how to implement this.</p>
<h3 id="heading-3-multi-factor-authentication">3. Multi-factor Authentication</h3>
<p>Also known as MFA, multi-factor authentication is an authentication method that requires a user to verify their identity by providing more than one piece of information that identifies them. This can range from something the user knows, has, or is.</p>
<p>This means that in addition to having a username and password, you will be required to provide extra proof depending on the system you are trying to access. This extra proof can range from a fingerprint to a secret security key or even a code generated randomly.</p>
<p>A good example of this authentication is when you set up an online banking system. Despite having entered a correct username and password, your might be required to either provide your fingerprint or even a code in order for some transaction to happen. </p>
<p>This means that even if someone was to obtain your username and password, they would still need your fingerprint or a code that has been sent to your phone in order to accomplish a specific task.</p>
<h3 id="heading-4-token-based-authentication">4. Token-Based Authentication</h3>
<p>Token-based authentication is a method of authenticating users that involves providing them with a unique token. This token can be used to identify the user and provide access to certain resources. The toke usually contains a string of characters generated by the system that's sent to the user's device or email.</p>
<p>There are many benefits to using token-based authentication, including improved security and scalability. </p>
<p>Tokens, while costly and inconvenient at times, provide a greater level of security than passwords or biometrics since they are only issued when requested. In addition to this, they can also be set to expire after a certain period of time, making it more secure compared to the traditional approaches.</p>
<p>This method is relatively new and it has become more popular in recent years as web applications have become more complex and distributed across multiple servers. It offers several other advantages over other methods.</p>
<p>With token-based authentication, the token is stored on the client side, making it much more secure. In addition, since there's no need to store tokens on the server, scaling becomes much easier.</p>
<p>Overall, token-based authentication offers better security and performance than other methods. If you're looking to implement an auth system for your web application, consider using tokens.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>User authentication is a critical part of any application, whether it's mobile or web. </p>
<p>It is important to choose an authentication method that is both secure and easy to use. </p>
<p>There are many different factors to consider when choosing an authentication method, but the most important thing is to choose one that will protect your users' data. Hopefully this article has given you some insights into how to do that.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Things You Should Know Before Enabling 2-Factor Authentication (2FA) ]]>
                </title>
                <description>
                    <![CDATA[ By Nitin Sharma With Cybersecurity becoming a big concern, two-factor authentication (2FA) is a topic that is becoming hotter with each passing day. After all, who doesn’t want to keep their private data safe? Two-factor authentication may not be a b... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/things-you-should-know-before-enabling-2-factor-authentication-2fa-6f11e4b5eab1/</link>
                <guid isPermaLink="false">66c3630baf2b7c40e7d7eb44</guid>
                
                    <category>
                        <![CDATA[ cybersecurity ]]>
                    </category>
                
                    <category>
                        <![CDATA[ passwords ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Security ]]>
                    </category>
                
                    <category>
                        <![CDATA[ technology ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Two-factor authentication ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 17 Dec 2018 17:13:46 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*2blNOZ7xEYZbq7px1K1lOg.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Nitin Sharma</p>
<p>With Cybersecurity becoming a big concern, two-factor authentication (2FA) is a topic that is becoming hotter with each passing day.</p>
<p>After all, who doesn’t want to keep their private data safe? Two-factor authentication may not be a bulletproof solution but is one of the easiest and best ways to shore up your virtual security.</p>
<p><strong>Treat 2-factor authentication as a supplement to strong passwords, not as a replacement.</strong></p>
<p>Two-factor authentication adds another security layer to the login process, reducing the chances of your account getting hacked. Just knowing and entering your password is not enough since there is a second layer which is usually time sensitive. This makes the process a whole lot more secure.</p>
<p>Here are some facts you would want to know before you enable two-factor authentication:</p>
<h4 id="heading-four-out-of-five-data-breaches-could-be-avoided-by-using-2fa">Four out of five data breaches could be avoided by using 2FA</h4>
<p>Cyber threats are on a rise and 2-factor authentication actually helps to counter them.</p>
<p>Majority of the hacking-related breaches take place due to weak or stolen passwords. Since many users tend to use the same password everywhere, the risk grows ten fold. Clearly, something more than just passwords are needed.</p>
<p>According to a <a target="_blank" href="http://www.verizonenterprise.com/resources/reports/rp_data-breach-investigations-report-2013_en_xg.pdf">Verizon’s Data Breach Report</a>, 80% of data breaches could be eliminated by the use of two-factor authentication.</p>
<p>2FA makes sure that even if your password gets compromised, the hacker has to crack another security layer before they can access your account. And since most of the 2FA methods are time-dependent, it makes the hacker’s job so much more difficult.</p>
<p>No wonder all the major websites and banks provide an option to enable 2-factor security.</p>
<h4 id="heading-two-factor-authentication-is-not-a-replacement-for-strong-passwords">Two-factor authentication is not a replacement for strong passwords</h4>
<p>Weak and repeated passwords are a bane to Cyber security. No matter which account or service you’re using, it’s always best to set a unique complex password.</p>
<p>Using repeated passwords all over the Internet makes us vulnerable to massive impacts even if one site’s security gets breached. In such a case, all our accounts can be at the attacker’s disposal.</p>
<p>Even if you enable two-factor authentication, strong passwords are a must. As mentioned earlier, treat 2FA as a supplement to strong passwords, not as a replacement.</p>
<p>Always use a complex combination of letters, numbers, and special symbols to generate a strong and unique password for each service you use. You can also use a service like <a target="_blank" href="https://www.lastpass.com/">LastPass</a> to easily manage your passwords.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/MgQT70g6WFU4xfJ6Ce5-OuuTvLDXmOckpiLD" alt="Image" width="800" height="438" loading="lazy">
<em>Facebook is one of the leading companies supporting two-factor authentication.</em></p>
<h4 id="heading-there-are-two-ways-you-can-get-the-passcodes">There are two ways you can get the passcodes</h4>
<p>You can generate the passcodes for 2FA in multiple ways. Codes can be generated on the server and then sent to you via Email, SMS or phone call. This usually requires network connectivity for your mobile and thus can leave you prone to inaccessible accounts in remote areas.</p>
<p>The other option is to generate the passcode offline on your phone or a hardware device. You can easily generate 2FA passcodes on your phone via apps like Google Authenticator, Authy or TOTP Authenticator. There are also hardware devices like YubiKey available in the market for setting up two-factor authentication.</p>
<p>This method is more robust as no data connectivity is required, leaving you less prone to network phishing.</p>
<p>In some cases, the second step can also be biometric verification or entering a PIN you set by yourself earlier.</p>
<h4 id="heading-always-back-up-you-dont-want-to-be-locked-out-of-your-account">Always back up. You don’t want to be locked out of your account</h4>
<p>2FA works on the premise that you always have access to the secondary passcode. But in case you use a 2-factor authentication app and you lose your phone or your data gets wiped out, you can be locked out of your account.</p>
<p>To avoid such a scenario, some websites provide backup codes which you must save securely and can use in such situations. Alternatively, you can use an authentication app which provides the option to back up your security key and related data.</p>
<p>We developed the TOTP Authentication app for iOS and Android keeping this in mind. The app allows you to back up your security key and related information either to your device or to online storage options such as Google Drive in a hassle free way. The encrypted backup file can be set up on another device with just a couple of taps. You can download the app from iTunes store from <a target="_blank" href="https://itunes.apple.com/us/app/totp-authenticator/id1404230533?mt=8">here</a>, and from Google Play Store from <a target="_blank" href="https://play.google.com/store/apps/details?id=com.authenticator.authservice2">here</a>.</p>
<h4 id="heading-conclusion">Conclusion</h4>
<p>Two-factor authentication is slowly becoming a norm in the digital world. Most of the banks, cloud storage services and social media websites already provide the option. You should switch on 2FA wherever possible. As they say, prevention is better than cure.</p>
<p>Have any questions about 2FA authentication? Shoot them in the comments!</p>
<p>To know more about 2-factor authentication you can also check out <a target="_blank" href="https://hackernoon.com/what-is-2-factor-authentication-and-why-you-should-care-e8af5808d499">this article</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How Time-based One-Time Passwords work and why you should use them in your app. ]]>
                </title>
                <description>
                    <![CDATA[ By Prakash Sharma With the increase in cyber security threats, it has become more and more necessary to upgrade the security standards of your web applications. You need to make sure your users’ accounts are safe. Nowadays, a lot of online web applic... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-time-based-one-time-passwords-work-and-why-you-should-use-them-in-your-app-fdd2b9ed43c3/</link>
                <guid isPermaLink="false">66c34ed2f41767c3c96bace0</guid>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Security ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ technology ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Two-factor authentication ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 18 Jun 2018 23:14:56 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*NtO_nq3H7lfuDd9nL9pRWg.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Prakash Sharma</p>
<p>With the increase in cyber security threats, it has become more and more necessary to upgrade the security standards of your web applications. You need to make sure your users’ accounts are safe.</p>
<p>Nowadays, a lot of online web applications are asking users to add an extra layer of security for their account. They do it by enabling 2-factor authentication. There are various methods of implementing 2-factor authentication, and TOTP (the Time-based One-Time Password algorithm) authentication is one of them.</p>
<p>This article explains what it is, and how and why to use it. But before understanding that, let’s first briefly take a look at what two-factor authentication means.</p>
<h3 id="heading-what-is-two-factor-authentication">What is Two Factor Authentication?</h3>
<p>Two-factor authentication (or multi factor authentication) is just an extra layer of security for a user’s account. That means that, after enabling two factor authentication, the user has to go through one more step to log in successfully. For example, the usual steps for logging in to an account are:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/ZqTllcloHTWpzWYDh-YsnOggoitxJSicGiVj" alt="Image" width="481" height="181" loading="lazy"></p>
<p>But after enabling 2-factor authentication, the steps look something like this:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/inJY5oemUFqSO2g5G6HvPpNt0I74XF0hlRKV" alt="Image" width="800" height="195" loading="lazy"></p>
<p>So this adds one more step to the login process. This method is more secure, because a criminal cannot access the user’s account unless they have access to both the user’s regular password and one time password.</p>
<p>Currently, there are two widely used methods to get that one time password:</p>
<ol>
<li><strong>SMS-based:</strong> In this method, every time the user logs in, they receive a text message to their registered phone number, which contains a One Time Password.</li>
<li><strong>TOTP-based:</strong> In this method, while enabling 2-factor authentication, the user is asked to scan a QR image using a specific smartphone application.<br>That application then continuously generates the One Time Password for the user.</li>
</ol>
<p>The SMS-based method does not need any explanation. It’s easy, but it has its own problems, like waiting for the SMS on every login attempt, security issues, and so on. The TOTP-based method is becoming popular because of it’s advantages over the SMS-based method. So let’s understand how the TOTP-based method works.</p>
<h3 id="heading-how-the-totp-based-method-works">How the TOTP-based method works</h3>
<p>Before understanding this, let’s first discuss what problems this method will solve for us.</p>
<p>By using the TOTP method, we are creating a one time password on the user side (instead of server side) through a smartphone application.</p>
<p>This means that users always have access to their one time password. So it prevents the server from sending a text message every time user tries to login.</p>
<p>Also, the generated password changes after a certain time interval, so it behaves like a one time password.</p>
<p>Great! Now let’s understand the workings of the TOTP-method and try to implement the above solution ourselves. Our requirement here is to create a password on the user side, and that password should keep changing.</p>
<p>The following could be a way to implement this solution:</p>
<pre><code>When the user enables two factor authentication:
</code></pre><pre><code><span class="hljs-number">1.</span> Backend server creates a secret key <span class="hljs-keyword">for</span> that particular user<span class="hljs-number">.2</span>. Server then shares that secret key <span class="hljs-keyword">with</span> the user’s phone application<span class="hljs-number">.3</span>. Phone application initializes a counter<span class="hljs-number">.4</span>. Phone application generate a one time password using that secret key and counter<span class="hljs-number">.5</span>. Phone application changes the counter after a certain interval and regenerates the one time password making it dynamic.
</code></pre><p>This should work, but there are three main problems with it:</p>
<ol>
<li>How will the application generate a one time password using a secret key and counter?</li>
<li>How will the counter update? How will the web server keep track of the counter?</li>
<li>How will the server share the secret key with the phone’s application?</li>
</ol>
<p>The solution to the first problem is defined in the HOTP algorithm.</p>
<h3 id="heading-understanding-hotp">Understanding HOTP:</h3>
<p>HOTP stands for “HMAC-Based One-Time Password”. This algorithm was published as <a target="_blank" href="https://tools.ietf.org/html/rfc4226">RFC4226</a> by the <a target="_blank" href="https://en.wikipedia.org/wiki/Internet_Engineering_Task_Force">Internet Engineering Task Force</a> (IETF). HOTP defines an algorithm to create a one time password from a secret key and a counter.</p>
<p>You can use this algorithm in two steps:</p>
<ol>
<li>The first step is to create an <a target="_blank" href="https://en.wikipedia.org/wiki/HMAC">HMAC</a> hash from a secret key and counter.</li>
</ol>
<pre><code><span class="hljs-comment">// Obtain HMAC hash (using SHA-1 hashing algorithm) by secretKey and counter</span>
</code></pre><pre><code>hmacHash = HMAC-SHA<span class="hljs-number">-1</span>(secretKey, counter);
</code></pre><ol start="2">
<li>In this code, the output would be a 20 byte long string. That long string is not suitable as a one time password. So we need a way to truncate that string. HOTP defines a way to truncate that string to our desired length.</li>
</ol>
<pre><code><span class="hljs-comment">// hmacHash[19] means 19th byte of the string.offset = hmacHash[19] &amp; 0xf;</span>
</code></pre><pre><code>truncatedHash = (hmacHash[offset++] &amp; <span class="hljs-number">0x7f</span>) &lt;&lt; <span class="hljs-number">24</span> | (hmacHash[offset++] &amp; <span class="hljs-number">0xff</span>) &lt;&lt; <span class="hljs-number">16</span> | (hmacHash[offset++] &amp; <span class="hljs-number">0xff</span>) &lt;&lt; <span class="hljs-number">8</span> | (hmacHashh[offset++] &amp; <span class="hljs-number">0xff</span>);
</code></pre><pre><code>finalOTP = (truncatedHash % (<span class="hljs-number">10</span> ^ numberOfDigitsRequiredInOTP));
</code></pre><p>It might look scary, but it is not. In this algorithm, we first obtain <code>offset</code> which is the last 4 bits of <code>hmacHash[19]</code>. After that, we concatenate the bytes from <code>hmacHash[offset]</code> to <code>hmacHash[offset+3]</code> and store the last 31 bits to <code>truncatedHash</code>. Finally, using a simple modulo operation, we obtain the one time password that’s a reasonable length.</p>
<p>This pretty much defines the HOTP algorithm. The <a target="_blank" href="https://tools.ietf.org/html/rfc4226">RFA4226</a> doc explains why this is the most secure way to obtain a one time password from these two values.</p>
<p>Great! So we have found a way to obtain a one time password using a secret key and counter. But what about the second problem? How to keep track of the counter?</p>
<p>The solution to second problem is found in the TOTP.</p>
<h3 id="heading-understanding-totp">Understanding TOTP:</h3>
<p>TOTP stands for “Time-Based One-Time Password”. This was published as <a target="_blank" href="https://tools.ietf.org/html/rfc6238">RFC6238</a> by <a target="_blank" href="https://en.wikipedia.org/wiki/Internet_Engineering_Task_Force">IETF</a>.</p>
<p>A TOTP uses the HOTP algorithm to obtain the one time password. The only difference is that it uses “Time” in the place of “counter,” and that gives the solution to our second problem.</p>
<p>That means that instead of initializing the counter and keeping track of it, we can use time as a counter in the HOTP algorithm to obtain the OTP. As a server and phone both have access to time, neither of them has to keep track of the counter.</p>
<p>Also, to avoid the problem of different time zones of the server and phone, we can use a <a target="_blank" href="https://en.wikipedia.org/wiki/Unix_time">Unix timestamp</a>, which is independent of time zones.</p>
<p>However the Unix time is defined in seconds, so it changes every second. That means the generated password will change every second which is not good. Instead, we need to add a significant interval before changing the password. For example, the Google Authenticator App changes the code every 30 seconds.</p>
<pre><code>counter = currentUnixTime / <span class="hljs-number">30</span>
</code></pre><p>So we have solved the problem of the counter. Now we need to address our third problem: sharing the secret key with the phone application. Here, a QR code can help us.</p>
<h3 id="heading-using-a-qr-code">Using a QR code</h3>
<p>Though we can ask the users to type the secret key into their phone application directly, we want to make secret keys quite long for security reasons. Asking the user to type in such a long string would not be a user friendly experience.</p>
<p>Since the majority of smartphones are equipped with a camera, we can use it and ask the user to scan a QR code to obtain the secret key from it. So all we need to do is to convert the secret key in the QR code and show it to the user.</p>
<p>We have solved all three problems! And now you know how TOTP works. Let’s see how to implement it in an application.</p>
<h3 id="heading-how-to-implement-totp">How to implement TOTP</h3>
<p>There are some free phone applications (like Google Authenticator App, Authy, and so on) available which can generate an OTP for the user. Therefore, in most cases, creating your own phone application is not necessary.</p>
<p>The following pseudo codes explain a way to implement TOTP-based 2-factor authentication in a web application.</p>
<pre><code>When user request to enable <span class="hljs-number">2</span>-factor authentication
</code></pre><pre><code><span class="hljs-comment">// Generate a secret key of length 20.secretKey = generateSecretKey(20);</span>
</code></pre><pre><code><span class="hljs-comment">// Save that secret key in database for this particular user.saveUserSecretKey(userId, secretKey);</span>
</code></pre><pre><code><span class="hljs-comment">// convert that secret key into qr image.qrCode = convertToQrCode(secretKey);</span>
</code></pre><pre><code><span class="hljs-comment">// send the qr image as responseresponse(qrCode);</span>
</code></pre><p>The user is asked to scan that QR code. When the phone application scans the QR code, it gets the user’s secret key. Using that secret key, the current Unix time, and the HOTP algorithm, the phone application will generate and display the password.</p>
<p>We ask the user to type the generated code after scanning the QR code. This is required, because we want to make sure that the user has successfully scanned the image and the phone application has successfully generated the code.</p>
<pre><code>User types the code displayed <span class="hljs-keyword">in</span> the application.
</code></pre><pre><code><span class="hljs-comment">// Fetch secret key from database.secretKey = getSecretKeyOfUser(userId);</span>
</code></pre><pre><code><span class="hljs-keyword">if</span> (codeTypedByUser == getHOTP(secretKey, currentUnixTime / <span class="hljs-number">30</span>)) {   enableTwoFactorAuthentication(userId);}
</code></pre><p>Here we use the HOTP algorithm on the server side to get the OTP-based authentication on the secret key and current unix time. If that OTP is the same as the one typed by the user, then we can enable 2-factor authentication for that user.</p>
<p>Now after every login operation, we need to check if this particular user has 2-factor authentication enabled. If it is enabled, then we ask for the one time password displayed in the phone application. And if that typed code is correct, only then is the user authenticated.</p>
<pre><code>User types the code displayed <span class="hljs-keyword">in</span> the phone application to login
</code></pre><pre><code><span class="hljs-comment">// Fetch secret key from database.secretKey = getSecretKeyOfUser(userId);</span>
</code></pre><pre><code><span class="hljs-keyword">if</span> (codeTypedByUser == getHOTP(secretKey, currentUnixTime)) {   signIn(userId);}
</code></pre><h3 id="heading-what-happens-if-the-user-loses-the-code">What happens if the user loses the code?</h3>
<p>There are a couple of ways to help the user to recover the code. Usually when they are enabling 2-factor authentication, we can show the secret key to them along with the QR code and ask them to save that code somewhere safely.</p>
<p>Applications like Google Authenticator App let you generate the password by directly entering the secret key. If the user loses the code, they can enter that safely saved secret key in the phone application to generate the OTP again.</p>
<p>If we have the user’s phone number, we can also use the SMS-based method to send an OTP to the user to help them recover the code.</p>
<h3 id="heading-wrapping-up">Wrapping Up</h3>
<p>Two factor authentication is gaining popularity. A lot of web applications are implementing it for extra security.</p>
<p>Unlike the SMS-based method, the TOTP method does not require a lot of extra effort either. So this feature is worth implementing for any application.</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
