<?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[ Flask Framework - 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[ Flask Framework - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Thu, 21 May 2026 16:11:09 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/flask/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ Build a Website Screenshot Generator with Python and Flask ]]>
                </title>
                <description>
                    <![CDATA[ Have you ever needed to take screenshots of websites automatically – maybe to track visual changes, include them in reports, or generate previews? Doing this manually can be time-consuming, especially if you need to capture multiple pages regularly. ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-a-website-screenshot-generator-with-python-and-flask/</link>
                <guid isPermaLink="false">690245c804c1e198e965b3ef</guid>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Flask Framework ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ashutosh Krishna ]]>
                </dc:creator>
                <pubDate>Wed, 29 Oct 2025 16:50:16 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1761756575904/17a940c5-352e-47a2-992e-a1973c030c05.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Have you ever needed to take screenshots of websites automatically – maybe to track visual changes, include them in reports, or generate previews? Doing this manually can be time-consuming, especially if you need to capture multiple pages regularly.</p>
<p>In this tutorial, you’ll learn how to build a simple website screenshot generator using Python and Flask. The app will let users enter any website URL and instantly get a screenshot of that page – all powered by a screenshot API.</p>
<p>You’ll use <a target="_blank" href="https://blog.ashutoshkrris.in/getting-started-with-flask"><strong>Flask</strong></a>, a lightweight web framework, to create a simple web interface and handle requests. Then, you’ll integrate an external API to capture website screenshots programmatically.</p>
<p>By the end of this tutorial, you’ll have learned how to:</p>
<ul>
<li><p>Build a basic Flask web app</p>
</li>
<li><p>Accept user input through an HTML form</p>
</li>
<li><p>Make HTTP requests to an external API</p>
</li>
<li><p>Display images dynamically on a web page</p>
</li>
</ul>
<p>This project is a great way to learn how APIs can extend the capabilities of your web applications, and how Python can easily handle tasks like image generation and display.</p>
<h3 id="heading-what-well-cover">What we’ll cover:</h3>
<ul>
<li><p><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-setting-up-the-project">Setting Up the Project</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-integrating-the-screenshotbase-api">Integrating the ScreenshotBase API</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-adding-customization-options">Adding Customization Options</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-wrapping-up">Wrapping Up</a></p>
</li>
</ul>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Before we start building the app, make sure you have a few basics covered:</p>
<h3 id="heading-1-python-installed">1. Python Installed</h3>
<p>You’ll need Python 3.9 or higher installed on your machine. You can check your version by running:</p>
<pre><code class="lang-bash">python --version
</code></pre>
<p>If you don’t have it, you can download it from <a target="_blank" href="https://www.python.org/downloads/">python.org/downloads</a>.</p>
<h3 id="heading-2-basic-knowledge-of-python-and-flask">2. Basic Knowledge of Python and Flask</h3>
<p>You don’t need to be a Flask expert. Just have some familiarity with how to create routes and templates, and how to handle form data in Flask.</p>
<p>If you’re new to Flask, don’t worry – we’ll go step-by-step.</p>
<h3 id="heading-3-screenshot-api-key">3. Screenshot API Key</h3>
<p>We’ll be using the <a target="_blank" href="https://screenshotbase.com/"><strong>ScreenshotBase API</strong></a> to capture website screenshots. It provides a simple REST endpoint that takes a URL and returns a screenshot image.</p>
<p>You can get a free API key by signing up on their website. Once you have the key, keep it handy, as we’ll use it when we integrate the API in the later steps.</p>
<h3 id="heading-4-a-code-editor-and-terminal">4. A Code Editor and Terminal</h3>
<p>You can use any editor you prefer, like VS Code, PyCharm, or even a simple text editor. Make sure your terminal or command prompt can run Python commands and install packages using <code>pip</code>.</p>
<h2 id="heading-setting-up-the-project">Setting Up the Project</h2>
<p>Let’s start by setting up a new Flask project from scratch.</p>
<h3 id="heading-step-1-create-a-new-folder">Step 1: Create a New Folder</h3>
<p>Create a new folder for your project. You can name it <code>screenshot-generator</code>:</p>
<pre><code class="lang-bash">mkdir screenshot-generator
<span class="hljs-built_in">cd</span> screenshot-generator
</code></pre>
<h3 id="heading-step-2-create-a-virtual-environment">Step 2: Create a Virtual Environment</h3>
<p>A virtual environment helps keep your project dependencies isolated from other Python projects.</p>
<p>Run the following commands:</p>
<pre><code class="lang-bash">python -m venv venv
</code></pre>
<p>Then activate it:</p>
<ul>
<li><p>On macOS/Linux:</p>
<pre><code class="lang-bash">  <span class="hljs-built_in">source</span> venv/bin/activate
</code></pre>
</li>
<li><p>On Windows:</p>
<pre><code class="lang-bash">  venv\Scripts\activate
</code></pre>
</li>
</ul>
<p>Once activated, you should see <code>(venv)</code> at the beginning of your terminal prompt.</p>
<h3 id="heading-step-3-install-dependencies">Step 3: Install Dependencies</h3>
<p>We’ll need two packages for this project:</p>
<ul>
<li><p><strong>Flask</strong> for building the web app</p>
</li>
<li><p><strong>Requests</strong> for making API calls to ScreenshotBase</p>
</li>
</ul>
<p>Install them using pip:</p>
<pre><code class="lang-bash">pip install flask requests
</code></pre>
<h3 id="heading-step-4-set-up-the-project-structure">Step 4: Set Up the Project Structure</h3>
<p>Inside your project folder, create the following files and folders:</p>
<pre><code class="lang-bash">screenshot-generator/
├── app.py
├── templates/
│   └── index.html
└── static/
</code></pre>
<p>Here’s what each part does:</p>
<ul>
<li><p><code>app.py</code>: main Python file that runs your Flask app</p>
</li>
<li><p><code>templates/</code>: stores HTML templates</p>
</li>
<li><p><code>static/</code>: stores images, CSS, and JavaScript files</p>
</li>
</ul>
<h3 id="heading-step-5-add-a-basic-flask-app">Step 5: Add a Basic Flask App</h3>
<p>Open <code>app.py</code> and add the following starter code:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> Flask, render_template, request
<span class="hljs-keyword">import</span> requests
<span class="hljs-keyword">import</span> os

app = Flask(__name__)
API_KEY = os.getenv(<span class="hljs-string">"SCREENSHOTBASE_API_KEY"</span>)
SCREENSHOTBASE_BASE_ENDPOINT = <span class="hljs-string">"https://api.screenshotbase.com/v1/take"</span>

<span class="hljs-meta">@app.route('/', methods=['GET', 'POST'])</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">home</span>():</span>
    <span class="hljs-keyword">if</span> request.method == <span class="hljs-string">'POST'</span>:
        url = request.form.get(<span class="hljs-string">'url'</span>)
        <span class="hljs-comment"># Placeholder: We’ll add the API call here in the next section</span>
        <span class="hljs-keyword">return</span> render_template(<span class="hljs-string">'index.html'</span>, url=url)
    <span class="hljs-keyword">return</span> render_template(<span class="hljs-string">'index.html'</span>)

<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:
    app.run(debug=<span class="hljs-literal">True</span>)
</code></pre>
<p>This sets up a minimal Flask application with one route (<code>/</code>). We’ll add the ScreenshotBase API call in the next section.</p>
<h3 id="heading-step-6-create-a-simple-html-template">Step 6: Create a Simple HTML Template</h3>
<p>Now that we’ve written the Flask backend to handle the screenshot request, let’s create the frontend for our app.</p>
<p>Inside your project folder, create a new directory named <code>templates</code>, and within it, add a file called <code>index.html</code>. Flask will automatically look for templates in this folder.</p>
<p>Here’s how the template should look:</p>
<pre><code class="lang-xml"><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">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-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Website Screenshot Generator<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&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.8/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-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB"</span>
      <span class="hljs-attr">crossorigin</span>=<span class="hljs-string">"anonymous"</span>
    /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="css">
        <span class="hljs-selector-tag">body</span> {
            <span class="hljs-attribute">padding-top</span>: <span class="hljs-number">2rem</span>;
        }
        <span class="hljs-selector-class">.screenshot-container</span> {
            <span class="hljs-attribute">max-height</span>: <span class="hljs-number">80vh</span>;
            <span class="hljs-attribute">overflow-y</span>: auto;
            <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid <span class="hljs-number">#ddd</span>;
            <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">8px</span>;
            <span class="hljs-attribute">padding</span>: <span class="hljs-number">1rem</span>;
            <span class="hljs-attribute">background</span>: <span class="hljs-number">#f8f9fa</span>;
        }
    </span><span class="hljs-tag">&lt;/<span class="hljs-name">style</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">body</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 text-center"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"mb-4"</span>&gt;</span>Website Screenshot Generator<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">method</span>=<span class="hljs-string">"POST"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"d-flex justify-content-center mb-4"</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">name</span>=<span class="hljs-string">"url"</span> 
                <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Enter website URL"</span> 
                <span class="hljs-attr">class</span>=<span class="hljs-string">"form-control w-50 me-2"</span>
                <span class="hljs-attr">required</span>
            &gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-primary"</span>&gt;</span>Capture Screenshot<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>

        {% if screenshot %}
            <span class="hljs-tag">&lt;<span class="hljs-name">h4</span>&gt;</span>Screenshot Preview:<span class="hljs-tag">&lt;/<span class="hljs-name">h4</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"screenshot-container mx-auto"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"{{ screenshot }}"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"Website Screenshot"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"img-fluid rounded shadow"</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        {% elif request.method == 'POST' %}
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"alert alert-danger mt-3"</span>&gt;</span>
                Sorry, something went wrong while capturing the screenshot. Please try again.
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</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">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>This HTML template uses Bootstrap to keep the design clean and responsive without much custom styling. The form at the top allows users to enter any website URL and submit it to the Flask app using the <code>POST</code> method. Once the app retrieves the screenshot URL from the API, it dynamically renders the image on the page.</p>
<p>The <code>img-fluid</code> class from Bootstrap ensures the screenshot scales properly across all screen sizes while maintaining its aspect ratio. Also, the <code>.screenshot-container</code> provides a scrollable area, which helps display full-page screenshots without shrinking them too much or breaking the layout.</p>
<p>Now your project is set up and ready to capture real screenshots using the ScreenshotBase API.</p>
<p>In the next section, we’ll write the logic to call the ScreenshotBase API and display the resulting screenshot dynamically in the browser.</p>
<h2 id="heading-integrating-the-screenshotbase-api">Integrating the ScreenshotBase API</h2>
<p>Now that our Flask app is set up, let’s connect it to the ScreenshotBase API so we can generate real screenshots from any URL.</p>
<h3 id="heading-step-1-understanding-the-api-endpoint">Step 1: Understanding the API Endpoint</h3>
<p>The ScreenshotBase API provides a simple endpoint that takes a website URL and returns a screenshot image.</p>
<p>A typical API call looks like this:</p>
<pre><code class="lang-bash">GET https://api.screenshotbase.com/v1/take
</code></pre>
<p>You send the target website URL as a query parameter (<code>url</code>) and include your API key in the request header as <code>apikey</code>.</p>
<p>Here’s the cURL example from their documentation:</p>
<pre><code class="lang-bash">curl -G https://api.screenshotbase.com/v1/take?url=https%3A%2F%2Fbbc.com \
    -H <span class="hljs-string">"apikey: YOUR-API-KEY"</span>
</code></pre>
<p>This request captures a screenshot of <code>https://bbc.com</code> and returns the screenshot image as the response.</p>
<h3 id="heading-step-2-add-the-api-call-in-flask">Step 2: Add the API Call in Flask</h3>
<p>Let’s update our <code>home</code> route in <code>app.py</code> to send a request to the ScreenshotBase API when a user submits a URL.</p>
<p>Here’s the updated version of <code>app.py</code>:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> Flask, render_template, request
<span class="hljs-keyword">import</span> requests
<span class="hljs-keyword">import</span> os

app = Flask(__name__)
API_KEY = os.getenv(<span class="hljs-string">"SCREENSHOTBASE_API_KEY"</span>)
SCREENSHOTBASE_BASE_ENDPOINT = <span class="hljs-string">"https://api.screenshotbase.com/v1/take"</span>

<span class="hljs-meta">@app.route('/', methods=['GET', 'POST'])</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">home</span>():</span>
    screenshot_url = <span class="hljs-literal">None</span>

    <span class="hljs-keyword">if</span> request.method == <span class="hljs-string">'POST'</span>:
        target_url = request.form.get(<span class="hljs-string">'url'</span>)

        params = {<span class="hljs-string">"url"</span>: target_url}
        headers = {<span class="hljs-string">"apikey"</span>: API_KEY}

        <span class="hljs-keyword">try</span>:
            <span class="hljs-comment"># Send GET request to ScreenshotBase API</span>
            response = requests.get(SCREENSHOTBASE_BASE_ENDPOINT, params=params, headers=headers, timeout=<span class="hljs-number">30</span>)
            response.raise_for_status()

            <span class="hljs-comment"># Save the returned image</span>
            image_path = os.path.join(<span class="hljs-string">'static'</span>, <span class="hljs-string">'screenshot.png'</span>)
            <span class="hljs-keyword">with</span> open(image_path, <span class="hljs-string">'wb'</span>) <span class="hljs-keyword">as</span> f:
                f.write(response.content)

            screenshot_url = image_path

        <span class="hljs-keyword">except</span> requests.exceptions.RequestException <span class="hljs-keyword">as</span> e:
            print(<span class="hljs-string">f"Error capturing screenshot: <span class="hljs-subst">{e}</span>"</span>)

    <span class="hljs-keyword">return</span> render_template(<span class="hljs-string">'index.html'</span>, screenshot=screenshot_url)

<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:
    app.run(debug=<span class="hljs-literal">True</span>)
</code></pre>
<p>Here’s what this code does:</p>
<ol>
<li><p>Captures the user input (URL).</p>
</li>
<li><p>Sends a GET request to the <code>/v1/take</code> endpoint.</p>
</li>
<li><p>Passes your API key in the request header (<code>apikey</code>).</p>
</li>
<li><p>Saves the returned image to the <code>static</code> folder.</p>
</li>
<li><p>Displays the screenshot on the page.</p>
</li>
</ol>
<h3 id="heading-step-3-test-your-app">Step 3: Test Your App</h3>
<p>Run the app again:</p>
<pre><code class="lang-python">python app.py
</code></pre>
<p>Then open <a target="_blank" href="http://127.0.0.1:5000">http://127.0.0.1:5000</a> in your browser.</p>
<p>Enter a URL like:</p>
<pre><code class="lang-python">https://github.com/ashutoshkrris
</code></pre>
<p>After submitting, you should see the screenshot of that website displayed below the form.</p>
<p>Your Flask app is now fully functional! It takes a URL, sends it to the ScreenshotBase API, and displays the resulting screenshot.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1761133080971/d0feb78c-09cb-4f01-b254-a56fca3a58c8.png" alt="d0feb78c-09cb-4f01-b254-a56fca3a58c8" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>In the next section, we’ll enhance the app by adding customization options like full-page screenshots, viewport settings, and delays. Later, we’ll explore the ScreenshotBase SDKs for popular languages like Python, Node.js, and PHP.</p>
<h2 id="heading-adding-customization-options">Adding Customization Options</h2>
<p>Right now, our app simply takes a screenshot of the given website URL using the default settings. However, most screenshot APIs (including the one we’re using) allow you to customize the output by passing additional parameters in the request.</p>
<p>The ScreenshotBase API offers several powerful customization options to help you tailor each screenshot to your needs:</p>
<ul>
<li><p><strong>Image format</strong>: Choose from <code>png</code>, <code>jpg</code>, <code>gif</code>, or <code>webp</code>, depending on your image quality or compression requirements.</p>
</li>
<li><p><strong>Full page capture</strong>: Capture the entire scrollable webpage (<code>full_page=1</code>) or just the visible viewport (<code>full_page=0</code>).</p>
</li>
<li><p><strong>Viewport dimensions</strong>: Set the browser window size with <code>viewport_width</code> and <code>viewport_height</code> to simulate screenshots from desktop, tablet, or mobile screens.</p>
</li>
</ul>
<p>These options make ScreenshotBase ideal for building automation tools, thumbnail generators, testing dashboards, and visual documentation systems. Let’s add these options to make our screenshot generator more flexible.</p>
<h3 id="heading-updating-the-flask-code">Updating the Flask Code</h3>
<p>Open your <code>app.py</code> file and update the route that handles form submissions to include these optional parameters:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> Flask, render_template, request
<span class="hljs-keyword">import</span> requests
<span class="hljs-keyword">import</span> os

app = Flask(__name__)
API_KEY = os.getenv(<span class="hljs-string">"SCREENSHOTBASE_API_KEY"</span>, <span class="hljs-string">"scr_live_9Qkn1gs01rivZqrFk7lusXPiqAUg85J86aU6bHvG"</span>)
SCREENSHOTBASE_BASE_ENDPOINT = <span class="hljs-string">"https://api.screenshotbase.com/v1/take"</span>


<span class="hljs-meta">@app.route('/', methods=['GET', 'POST'])</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">home</span>():</span>
    screenshot_url = <span class="hljs-literal">None</span>

    <span class="hljs-keyword">if</span> request.method == <span class="hljs-string">'POST'</span>:
        target_url = request.form.get(<span class="hljs-string">'url'</span>)
        format_ = request.form.get(<span class="hljs-string">'format'</span>, <span class="hljs-string">'png'</span>)
        full_page = request.form.get(<span class="hljs-string">'full_page'</span>) == <span class="hljs-string">'on'</span>

        params = {
            <span class="hljs-string">"url"</span>: target_url,
            <span class="hljs-string">"format"</span>: format_,
            <span class="hljs-string">"full_page"</span>: int(full_page)
        }
        headers = {<span class="hljs-string">"apikey"</span>: API_KEY}

        <span class="hljs-keyword">try</span>:
            <span class="hljs-comment"># Send GET request to ScreenshotBase API</span>
            response = requests.get(SCREENSHOTBASE_BASE_ENDPOINT, params=params, headers=headers, timeout=<span class="hljs-number">30</span>)
            response.raise_for_status()

            <span class="hljs-comment"># Save the returned image</span>
            image_extension = format_ <span class="hljs-keyword">if</span> format_ != <span class="hljs-string">'jpeg'</span> <span class="hljs-keyword">else</span> <span class="hljs-string">'jpg'</span>
            image_path = os.path.join(<span class="hljs-string">'static'</span>, <span class="hljs-string">f'screenshot.<span class="hljs-subst">{image_extension}</span>'</span>)
            <span class="hljs-keyword">with</span> open(image_path, <span class="hljs-string">'wb'</span>) <span class="hljs-keyword">as</span> f:
                f.write(response.content)

            screenshot_url = image_path

        <span class="hljs-keyword">except</span> requests.exceptions.RequestException <span class="hljs-keyword">as</span> e:
            print(<span class="hljs-string">f"Error capturing screenshot: <span class="hljs-subst">{e}</span>"</span>)

    <span class="hljs-keyword">return</span> render_template(<span class="hljs-string">'index.html'</span>, screenshot=screenshot_url)


<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:
    app.run(debug=<span class="hljs-literal">True</span>)
</code></pre>
<h3 id="heading-updating-the-html-template">Updating the HTML Template</h3>
<p>Next, let’s modify the form in our <code>index.html</code> to include the customization options:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">method</span>=<span class="hljs-string">"POST"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"d-flex flex-column justify-content-center mb-4"</span>&gt;</span>
  <span class="hljs-comment">&lt;!-- URL and Submit Button in One Row --&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"input-group mb-4"</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">name</span>=<span class="hljs-string">"url"</span>
      <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Enter website URL"</span>
      <span class="hljs-attr">class</span>=<span class="hljs-string">"form-control w-50 me-2"</span>
      <span class="hljs-attr">required</span>
    /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-primary"</span>&gt;</span>Capture Screenshot<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-comment">&lt;!-- Options in Two Columns --&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"row g-3"</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- Full Page Checkbox --&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-6"</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-check"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
          <span class="hljs-attr">type</span>=<span class="hljs-string">"checkbox"</span>
          <span class="hljs-attr">name</span>=<span class="hljs-string">"full_page"</span>
          <span class="hljs-attr">id</span>=<span class="hljs-string">"full_page"</span>
          <span class="hljs-attr">class</span>=<span class="hljs-string">"form-check-input"</span>
        /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-check-label"</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"full_page"</span>&gt;</span>
          Capture Full Page Screenshot
        <span class="hljs-tag">&lt;/<span class="hljs-name">label</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>

    <span class="hljs-comment">&lt;!-- Format Dropdown --&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-6"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"format"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-label"</span>&gt;</span>Screenshot Format<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">select</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-select"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"format"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"format"</span> <span class="hljs-attr">required</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"png"</span>&gt;</span>PNG<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"jpg"</span>&gt;</span>JPG<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"gif"</span>&gt;</span>GIF<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"webp"</span>&gt;</span>WEBP<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">select</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

    <span class="hljs-comment">&lt;!-- Viewport Width --&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-6"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"viewport_width"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-label"</span>&gt;</span>Viewport Width<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">"number"</span>
        <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport_width"</span>
        <span class="hljs-attr">id</span>=<span class="hljs-string">"viewport_width"</span>
        <span class="hljs-attr">class</span>=<span class="hljs-string">"form-control"</span>
        <span class="hljs-attr">value</span>=<span class="hljs-string">"1280"</span>
        <span class="hljs-attr">min</span>=<span class="hljs-string">"320"</span>
      /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

    <span class="hljs-comment">&lt;!-- Viewport Height --&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-6"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"viewport_height"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-label"</span>&gt;</span>Viewport Height<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">"number"</span>
        <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport_height"</span>
        <span class="hljs-attr">id</span>=<span class="hljs-string">"viewport_height"</span>
        <span class="hljs-attr">class</span>=<span class="hljs-string">"form-control"</span>
        <span class="hljs-attr">value</span>=<span class="hljs-string">"720"</span>
        <span class="hljs-attr">min</span>=<span class="hljs-string">"320"</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>
<span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
</code></pre>
<p>The updated form gives users control over how the screenshot is generated. The format dropdown lets them choose between PNG, JPG, GIF, or WEBP. The Full Page checkbox toggles whether the API captures the entire scrollable webpage or just the visible viewport. The viewport width and height fields define the browser window dimensions, which is useful if you want to simulate different device sizes or responsive layouts.</p>
<p>When the form is submitted, Flask reads these values and sends them as query parameters in the API request.</p>
<p>For example, a request to capture a full-page, 1920×1080 PNG screenshot of your site would look like this:</p>
<pre><code class="lang-xml">https://api.screenshotbase.com/v1/take?url=https%3A%2F%2Fgithub.com%2Fashutoshkrris&amp;format=png&amp;full_page=1&amp;viewport_width=1920&amp;viewport_height=1080
</code></pre>
<p>This flexibility makes it easy to fine-tune screenshots for different use cases – whether you’re generating thumbnails, testing responsiveness, or automating visual reports.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1761134646387/b9145271-303f-408e-ab53-444ea125849e.gif" alt="b9145271-303f-408e-ab53-444ea125849e" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Note: If you prefer working with SDKs instead of direct API calls, ScreenshotBase also offers official SDKs for popular languages like Python, JavaScript, Ruby, PHP, and Go.</p>
<p>These SDKs provide a simpler and more convenient way to interact with the API, handling authentication and request formatting behind the scenes.</p>
<p>You can explore them in the <a target="_blank" href="https://screenshotbase.com/docs/sdks">ScreenshotBase SDK documentation</a>.</p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>In this tutorial, you learned how to build a simple Flask application that captures website screenshots using a third-party API. We explored how to send requests, handle image responses, and add customization options like image format, full-page capture, and viewport size – all while keeping the project lightweight and easy to extend.</p>
<p>This small project demonstrates how web automation tasks, such as generating previews or visual reports, can be simplified using modern APIs. You can build upon this foundation to create batch screenshot tools, visual monitoring systems, or even integrate screenshots into larger web applications.</p>
<p>The key takeaway is understanding how to interact with external APIs, process responses, and design a clean interface for users. These are skills that are essential for backend and full-stack developers alike.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How To Implement Instant Search with Flask and HTMX ]]>
                </title>
                <description>
                    <![CDATA[ Instant search is a feature that shows search results as users type their query. Instead of waiting for a full page reload or submitting a form, results appear instantly, allowing users to find what they are looking for quickly. For example, when you... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-implement-instant-search-with-flask-and-htmx/</link>
                <guid isPermaLink="false">66ba0e96102ebf67c0a6d42a</guid>
                
                    <category>
                        <![CDATA[ Flask Framework ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ashutosh Krishna ]]>
                </dc:creator>
                <pubDate>Mon, 22 Jul 2024 11:36:53 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/07/instant-search.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Instant search is a feature that shows search results as users type their query. Instead of waiting for a full page reload or submitting a form, results appear instantly, allowing users to find what they are looking for quickly. For example, when you start typing in a search box, suggestions or matching items will appear immediately, making the process smoother and more efficient.</p>
<p>In this tutorial, you'll learn how to create a simple instant search feature using Flask and HTMX. This will help you build interactive web applications with better user experience.</p>
<h2 id="heading-table-of-contents">Table of Contents:</h2>
<ol>
<li><a class="post-section-overview" href="#heading-how-to-set-up-the-environment">How to Set Up the Environment</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-the-database">How to Set up the Database</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-basic-routing-and-html">How to Set Up Basic Routing and HTML</a></li>
<li><a class="post-section-overview" href="#heading-how-to-add-htmx-for-instant-search">How to Add HTMX for Instant Search</a></li>
<li><a class="post-section-overview" href="#heading-demo">Demo</a></li>
<li><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></li>
</ol>
<h3 id="heading-why-use-instant-search"><strong>Why Use Instant Search?</strong></h3>
<ul>
<li><strong>Speed</strong>: Users get immediate feedback, which helps them refine their search.</li>
<li><strong>Convenience</strong>: It reduces the number of clicks and page loads, leading to a more seamless experience.</li>
<li><strong>Engagement</strong>: Users are more likely to stay on your site if they can find what they need easily.</li>
</ul>
<h3 id="heading-technologies-used"><strong>Technologies Used</strong></h3>
<p>To implement this instant search feature, we'll use two main technologies:</p>
<ul>
<li><strong>Flask</strong>: <a target="_blank" href="https://blog.ashutoshkrris.in/getting-started-with-flask">Flask</a> is a popular web framework for Python. It is simple and lightweight, making it easy to set up and start building web applications quickly. Flask lets you to create routes, handle requests, and serve HTML templates with minimal setup.</li>
<li><strong>HTMX</strong>: This is a powerful JavaScript library that lets you to create dynamic web pages without having to write a lot of JavaScript code. With HTMX, you can update parts of a page based on user actions, like typing in a search box. It makes it easy to load data from the server and display it on the page without a full reload.</li>
</ul>
<h2 id="heading-how-to-set-up-the-environment">How to Set Up the Environment</h2>
<p>In this section, we'll set up the environment for our Flask project, including installing the necessary packages and organizing the project structure.</p>
<h4 id="heading-1-how-to-install-flask-and-htmx">1. How to Install Flask and HTMX</h4>
<p>First, you need to install Flask, Flask-SQLAlchemy, and Flask-Migrate. You can do this using pip. Open your terminal and run:</p>
<pre><code class="lang-bash">pip install Flask Flask-SQLAlchemy Flask-Migrate
</code></pre>
<p>For HTMX, we'll include it in our HTML template directly from a CDN.</p>
<h4 id="heading-2-how-to-create-a-virtual-environment">2. How to Create a Virtual Environment</h4>
<p>It's a good practice to create a virtual environment for your projects to manage dependencies. Here's how to create one:</p>
<pre><code class="lang-bash">python -m venv venv
</code></pre>
<p>Next, activate the environment:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># On Windows</span>
venv\Scripts\activate

<span class="hljs-comment"># On macOS/Linux</span>
<span class="hljs-built_in">source</span> venv/bin/activate
</code></pre>
<h4 id="heading-3-how-to-set-up-the-project-structure">3. How to Set Up the Project Structure</h4>
<p>Now, set up your project structure as follows:</p>
<pre><code class="lang-bash">my_flask_app/
├── core/
│   ├── __init__.py
│   ├── models.py
│   └── routes.py
├── config.py
└── main.py
</code></pre>
<p>Let us start with creating the first file: <strong>core/<strong>init</strong>.py</strong>. This file is the initialization script for the core module of our Flask application. It sets up the Flask app instance and configures it using the settings from the <code>DevelopmentConfig</code> class, and initializes the database and migration system.</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> Flask
<span class="hljs-keyword">from</span> flask_sqlalchemy <span class="hljs-keyword">import</span> SQLAlchemy
<span class="hljs-keyword">from</span> flask_migrate <span class="hljs-keyword">import</span> Migrate
<span class="hljs-keyword">from</span> config <span class="hljs-keyword">import</span> DevelopmentConfig

<span class="hljs-comment"># Create the Flask app instance</span>
app = Flask(__name__)

<span class="hljs-comment"># Load configuration from DevelopmentConfig</span>
app.config.from_object(DevelopmentConfig)

<span class="hljs-comment"># Initialize SQLAlchemy with the app instance</span>
db = SQLAlchemy(app)

<span class="hljs-comment"># Initialize Flask-Migrate with the app instance and database</span>
migrate = Migrate(app, db)

<span class="hljs-comment"># Import routes to register them with the app</span>
<span class="hljs-keyword">from</span> core <span class="hljs-keyword">import</span> routes
</code></pre>
<p>Next, we will create the <strong>config.py</strong> file from where we'll import the <code>DevelopmentConfig</code> class. This file contains configuration settings for different environments (development, testing, production). These settings help manage different behaviors and configurations based on where your app is running.</p>
<pre><code class="lang-python"><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 = <span class="hljs-string">"guess-me"</span>
    SQLALCHEMY_DATABASE_URI = <span class="hljs-string">"sqlite:///db.sqlite"</span>
    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>

<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>
<ul>
<li><code>Config</code>: The base configuration class with default settings.</li>
<li><code>DevelopmentConfig</code>: Inherits from <code>Config</code> and overrides development settings.</li>
<li><code>TestingConfig</code>: Inherits from <code>Config</code> and overrides settings for testing.</li>
<li><code>ProductionConfig</code>: Inherits from <code>Config</code> and overrides production settings.</li>
</ul>
<p>Finally, we'll create the <strong>main.py</strong> file. This is the entry point of our application. When we run this file, it starts the Flask web server.</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> core <span class="hljs-keyword">import</span> app

<span class="hljs-comment"># Start the Flask app</span>
<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:
    app.run(debug=<span class="hljs-literal">True</span>)
</code></pre>
<ul>
<li><code>if __name__ == '__main__'</code>: This ensures that the Flask app runs only if the script is executed directly (not imported as a module).</li>
<li><code>app.run(debug=True)</code>: Starts the Flask development server with debug mode enabled, which provides detailed error messages and auto-reloading.</li>
</ul>
<p>Now that you understand the project files, we can proceed with implementing the instant search functionality. This will involve creating the models and search route, setting up the HTMX-powered front-end, and connecting everything to fetch and display search results dynamically.</p>
<h2 id="heading-how-to-set-up-the-database">How to Set up the Database</h2>
<p>In this section, we will set up the database for our Flask application. We will use SQLite for simplicity. We will create a model for the data we want to search and seed the database with sample data.</p>
<p>SQLite is a lightweight, disk-based database that doesn’t require a separate server process. It's an excellent choice for development and small projects because it is easy to set up and use.</p>
<h3 id="heading-how-to-create-a-model-for-the-data-to-be-searched">How to Create a Model for the Data to Be Searched</h3>
<p>We will create a <code>Book</code> model to represent the data in our database. This model will include fields like the book title and author.</p>
<p>Let's create the <code>core/models.py</code> file and add the model there:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> core <span class="hljs-keyword">import</span> db

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Book</span>(<span class="hljs-params">db.Model</span>):</span>
    id = db.Column(db.Integer, primary_key=<span class="hljs-literal">True</span>)
    title = db.Column(db.String(<span class="hljs-number">100</span>), nullable=<span class="hljs-literal">False</span>)
    author = db.Column(db.String(<span class="hljs-number">100</span>), nullable=<span class="hljs-literal">False</span>)
</code></pre>
<h3 id="heading-how-to-apply-migrations-using-flask-migrate">How to Apply Migrations Using Flask-Migrate</h3>
<p>Before we can seed our database, we need to set up database migrations using Flask-Migrate. This tool helps us manage database changes, such as creating tables and altering schemas, systematically.</p>
<p>Initialize the migrations folder by running the following command in your project directory:</p>
<pre><code class="lang-bash">flask db init
</code></pre>
<p>This command creates a <strong>migrations</strong> directory in our project, which will store migration scripts.</p>
<p>Generate a migration script that creates the necessary database tables based on your models:</p>
<pre><code class="lang-bash">flask db migrate -m <span class="hljs-string">"Initial migration"</span>
</code></pre>
<p>This command scans your models and generates a new migration script in the <strong>migrations</strong> folder.</p>
<p>Apply the migration to create the tables in your database:</p>
<pre><code class="lang-bash">flask db upgrade
</code></pre>
<p>This command executes the migration script, creating the tables defined by your models in the database. Post this step, you will see an <strong>instance/db.sqlite</strong> file created.</p>
<h3 id="heading-how-to-seed-data-into-your-database">How to Seed Data Into Your Database</h3>
<p>Now that we have set up the database and applied the migration, we can proceed with seeding the database. Create a file named <strong>seeder.py</strong> with the following content:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> csv
<span class="hljs-keyword">from</span> sqlalchemy.exc <span class="hljs-keyword">import</span> IntegrityError

<span class="hljs-keyword">from</span> core <span class="hljs-keyword">import</span> db, app
<span class="hljs-keyword">from</span> core.models <span class="hljs-keyword">import</span> Book


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">seed_data</span>():</span>
    <span class="hljs-keyword">with</span> app.app_context():
        <span class="hljs-comment"># Open the CSV file</span>
        <span class="hljs-keyword">with</span> open(<span class="hljs-string">"data.csv"</span>, newline=<span class="hljs-string">''</span>, encoding=<span class="hljs-string">'utf-8'</span>) <span class="hljs-keyword">as</span> csvfile:
            reader = csv.DictReader(csvfile)

            <span class="hljs-comment"># Iterate over the rows in the CSV file</span>
            <span class="hljs-keyword">for</span> row <span class="hljs-keyword">in</span> reader:
                <span class="hljs-comment"># Create a new Book instance</span>
                book = Book(
                    title=row[<span class="hljs-string">'Book Name'</span>],
                    author=row[<span class="hljs-string">'Author Name'</span>]
                )

                <span class="hljs-comment"># Add the book to the session</span>
                db.session.add(book)

            <span class="hljs-keyword">try</span>:
                <span class="hljs-comment"># Commit the session to write the books to the database</span>
                db.session.commit()
                print(<span class="hljs-string">"Books added successfully."</span>)
            <span class="hljs-keyword">except</span> IntegrityError <span class="hljs-keyword">as</span> e:
                db.session.rollback()
                print(<span class="hljs-string">f"Error occurred: <span class="hljs-subst">{e}</span>"</span>)


<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>:
    seed_data()
</code></pre>
<p>The seeder script is responsible for populating the database with initial data. This is useful for testing and development purposes, allowing you to work with a set of sample data. This script reads data from <strong>data.csv</strong>, and processes it to insert it into the database.</p>
<p><strong>Note</strong>: You can download the <a target="_blank" href="https://github.com/ashutoshkrris/instant-search-with-flask-htmx/blob/main/data.csv">data.csv</a> file from here.</p>
<p>To use this script, ensure your <strong>data.csv</strong> file exists in the same directory as <strong>seeder.py</strong>. Run the script using Python:</p>
<pre><code class="lang-bash">python seeder.py
</code></pre>
<h2 id="heading-how-to-set-up-basic-routing-and-html">How to Set Up Basic Routing and HTML</h2>
<p>In this section, we'll set up a basic route in Flask to serve an index page (<strong>index.html</strong>) where users can search and display books.</p>
<h3 id="heading-how-to-set-up-flask-route">How to Set Up Flask Route</h3>
<p>Let's set up a Flask route (<code>/</code>) to render an <strong>index.html</strong> template and display books. For that, create a <strong>core/routes.py</strong> file and add the following route:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> render_template
<span class="hljs-keyword">from</span> core <span class="hljs-keyword">import</span> app
<span class="hljs-keyword">from</span> core.models <span class="hljs-keyword">import</span> Book

<span class="hljs-meta">@app.route('/')</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">index</span>():</span>
    <span class="hljs-comment"># Fetch the first 20 books to display by default</span>
    books = Book.query.limit(<span class="hljs-number">20</span>).all()
    <span class="hljs-keyword">return</span> render_template(<span class="hljs-string">"index.html"</span>, books=books)
</code></pre>
<p>The Flask application handles routing through the <code>@app.route('/')</code> decorator, which directs requests to the root URL (<code>/</code>). When a user visits the homepage, the <code>index()</code> function is invoked. </p>
<p>Inside this function, we query the <code>Book</code> model using SQLAlchemy to fetch the first 20 books from the database. These books are then passed as a parameter (<code>books</code>) to the <code>render_template</code> function, which renders the <strong>index.html</strong> template.</p>
<h3 id="heading-how-to-creating-the-indexhtml-template">How to Creating the index.html Template</h3>
<p>Create a file named <strong>index.html</strong> inside a <strong>templates</strong> directory in your project. The <strong>templates</strong> directory will lie in the <code>core</code> package. This file will contain the HTML structure for our book search page.</p>
<pre><code class="lang-xml"><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">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.0"</span> /&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Book Search<span class="hljs-tag">&lt;/<span class="hljs-name">title</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">"https://cdn.jsdelivr.net/npm/bulma@0.9.4/css/bulma.min.css"</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">body</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">section</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"section"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"columns"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"column is-one-third is-offset-one-third"</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">"input"</span> <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Search"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"query"</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>
    <span class="hljs-tag">&lt;<span class="hljs-name">table</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"table is-fullwidth"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">thead</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>ID<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>Book Title<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>Book Author<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">thead</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">tbody</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"results"</span>&gt;</span>
        {% for book in books %}
        <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>{{ book.id }}<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>{{ book.title }}<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>{{ book.author }}<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
        {% endfor %}
      <span class="hljs-tag">&lt;/<span class="hljs-name">tbody</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">table</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span>
<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>This HTML file uses the Bulma CSS framework for styling and includes elements such as an input field for user searches and a table to display book details fetched from the database.</p>
<p>The <code>index.html</code> template utilizes Jinja2 templating to dynamically populate the table rows (<code>&lt;tr&gt;</code>) with book data retrieved from the Flask backend. Each book's <code>ID</code>, <code>title</code>, and <code>author</code> are displayed in the table rows using <code>{{</code><a target="_blank" href="http://book.id"><code>book.id</code></a><code>}}</code>, <code>{{ book.title }}</code>, and <code>{{</code><a target="_blank" href="http://book.author"><code>book.author</code></a><code>}}</code> respectively.</p>
<h3 id="heading-how-to-run-the-application">How to Run the Application</h3>
<p>Let's run the application using the following command:</p>
<pre><code class="lang-bash">flask run
</code></pre>
<p>Once your application is up and running, this what how it should look like:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721316465728/d5037fd3-f49b-4c59-993c-4ff7c23cabef.png" alt="Book Search Application Home Page" width="1918" height="937" loading="lazy">
<em>web page with ID, book titles, and book authors</em></p>
<h2 id="heading-how-to-add-htmx-for-instant-search">How to Add HTMX for Instant Search</h2>
<p>Finally, we'll add HTMX to enhance our Flask application with dynamic search capabilities. For this, we'll introduce a new route and modify existing HTML template.</p>
<h3 id="heading-how-to-create-the-search-route">How to Create the Search Route</h3>
<p>First, create a new route <code>/search</code> in your Flask application to handle book searches based on user input:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> render_template, request
<span class="hljs-keyword">from</span> core <span class="hljs-keyword">import</span> app
<span class="hljs-keyword">from</span> core.models <span class="hljs-keyword">import</span> Book

<span class="hljs-meta">@app.route('/search')</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">search</span>():</span>
    query = request.args.get(<span class="hljs-string">"query"</span>)
    <span class="hljs-keyword">if</span> query:
        results = Book.query.filter(Book.title.ilike(<span class="hljs-string">f"%<span class="hljs-subst">{query}</span>%"</span>) | Book.author.ilike(<span class="hljs-string">f"%<span class="hljs-subst">{query}</span>%"</span>)).limit(<span class="hljs-number">10</span>).all()
    <span class="hljs-keyword">else</span>:
        results = Book.query.limit(<span class="hljs-number">20</span>).all()
    <span class="hljs-keyword">return</span> render_template(<span class="hljs-string">"search_results.html"</span>, results=results)
</code></pre>
<p>This route listens for <code>GET</code> requests to <code>/search</code>. It retrieves the search query from the URL parameter using <code>request.args.get("query")</code>. </p>
<p>If a <code>query</code> parameter is present, it uses SQLAlchemy's <code>ilike</code> method to perform a case-insensitive search across the <code>title</code> and <code>author</code> columns of the <code>Book</code> table, fetching up to 10 results.</p>
<p>If no query parameter is provided, it defaults to fetching the first 20 books from the database. The results are passed to a new <code>search_results.html</code> template for rendering.</p>
<h3 id="heading-how-to-modify-indexhtml-to-add-htmx">How to Modify index.html to Add HTMX</h3>
<pre><code class="lang-xml"><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">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.0"</span> /&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Book Search<span class="hljs-tag">&lt;/<span class="hljs-name">title</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">"https://cdn.jsdelivr.net/npm/bulma@0.9.4/css/bulma.min.css"</span> /&gt;</span>
  <span class="hljs-comment">&lt;!-- Include HTMX library --&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/htmx.org/dist/htmx.min.js"</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">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">section</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"section"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"columns"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"column is-one-third is-offset-one-third"</span>&gt;</span>
        <span class="hljs-comment">&lt;!-- HTMX-enabled search input --&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">"input"</span>
            <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Search"</span>
            <span class="hljs-attr">name</span>=<span class="hljs-string">"query"</span>
            <span class="hljs-attr">hx-get</span>=<span class="hljs-string">"/search"</span>
            <span class="hljs-attr">hx-trigger</span>=<span class="hljs-string">"keyup changed delay:500ms"</span>
            <span class="hljs-attr">hx-target</span>=<span class="hljs-string">"#results"</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>
    <span class="hljs-tag">&lt;<span class="hljs-name">table</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"table is-fullwidth"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">thead</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>ID<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>Book Title<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>Book Author<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">thead</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">tbody</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"results"</span>&gt;</span>
        {% for book in books %}
          <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>{{ book.id }}<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>{{ book.title }}<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>{{ book.author }}<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
        {% endfor %}
      <span class="hljs-tag">&lt;/<span class="hljs-name">tbody</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">table</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span>
<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>&lt;script&gt;</code> tag imports the HTMX library from a CDN, enabling client-side interactions without requiring complex JavaScript. In addition to that, we enhanced the <code>&lt;input&gt;</code> element with HTMX attributes:</p>
<ul>
<li><code>hx-get="/search"</code>: Specifies the endpoint (<code>/search</code>) to send GET requests when the user types in the input field.</li>
<li><code>hx-trigger="keyup changed delay:500ms"</code>: Triggers the search action after a 500ms delay when the user types (<code>keyup</code>) or changes the input (<code>changed</code>).</li>
<li><code>hx-target="#results"</code>: Updates the content of the element with <code>id="results"</code> with the response from the <code>/search</code> endpoint.</li>
</ul>
<h3 id="heading-how-to-create-the-searchresultshtml-template">How to Create the search_results.html Template</h3>
<p>Next, we will create a new template <strong>search_results.html</strong> to display search results:</p>
<pre><code class="lang-xml">{% for result in results %}
<span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>{{ result.id }}<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>{{ result.title }}<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>{{ result.author }}<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
{% endfor %}
</code></pre>
<p>This template iterates over <code>results</code>, which are passed from the <code>/search</code> route. For each book in <code>results</code>, generates a table row (<code>&lt;tr&gt;</code>) that displays the book's ID, title, and author.</p>
<h2 id="heading-demo">Demo</h2>
<p>Finally, we have implemented instant search with HTMX in our Flask application. Here's what our final application should look like:</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/llCmZXaopX0" 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>You'd notice a delay in the search results. This is called debouncing. It is a technique used in programming and web development to limit the rate at which a function or event handler is executed. It ensures that a function is only executed after a certain amount of time has passed since the last invocation of the function. </p>
<p>In our case, we set the delay to 500ms before it calls the <code>/search</code> API again. This ensures that we do not hit the API for every character the user types.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this tutorial, you learned how to implement instant search using Flask and HTMX, focusing on enhancing user interaction and performance. By integrating HTMX for AJAX interactions, we enabled dynamic updates to search results without refreshing the entire page. </p>
<p>This approach not only improves user experience by providing real-time feedback but also optimizes server load by debouncing search queries. </p>
<p>By mastering these techniques, you're equipped to build responsive web applications that deliver seamless search experiences, combining the flexibility of Flask with the interactivity of HTMX to meet diverse user needs efficiently and effectively.</p>
<p>You can find the code for this tutorial in this repository: <a target="_blank" href="https://github.com/ashutoshkrris/instant-search-with-flask-htmx">https://github.com/ashutoshkrris/instant-search-with-flask-htmx</a></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use JSON Web Tokens for Secure Authentication in Flask Applications ]]>
                </title>
                <description>
                    <![CDATA[ Passwords, credit card information, personal identification numbers (PINs) – these are all critical assets used for authorization and authentication. This means they need to be protected from unauthorized users. As developers, we are tasked with safe... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/jwt-authentication-in-flask/</link>
                <guid isPermaLink="false">66c37432ad70110156766fe4</guid>
                
                    <category>
                        <![CDATA[ authentication ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Flask Framework ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JSON Web Tokens ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JWT ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Security ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Yemi Ojedapo ]]>
                </dc:creator>
                <pubDate>Wed, 17 Apr 2024 16:29:02 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/04/pexels-soumil-kumar-735911--1-.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Passwords, credit card information, personal identification numbers (PINs) – these are all critical assets used for authorization and authentication. This means they need to be protected from unauthorized users.</p>
<p>As developers, we are tasked with safeguarding these sensitive bits of info, and it's important to implement strong secure measures in our applications. </p>
<p>Now, there are many authentication mechanisms available for securing data, like OAuth, OpenID Connect, and JSON Web Tokens (JWTs).</p>
<p>In this article, I'll show you how to use JWTs when securing information in APIs by integrating JWT-based authentication in a Flask application. </p>
<p>Here's what this article will cover:</p>
<ul>
<li><a class="post-section-overview" href="#heading-what-is-a-json-web-token">What is a JSON Web Token?</a></li>
<li><a class="post-section-overview" href="#heading-how-do-jwts-work">How Do JWTs Work?</a></li>
<li><a class="post-section-overview" href="#heading-how-to-use-json-web-tokens-to-authenticate-flask-applications">How to Use JSON Web Tokens to Authenticate Flask Applications</a>  </li>
<li><a class="post-section-overview" href="#heading-1-install-the-dependencies">Install dependencies</a>  </li>
<li><a class="post-section-overview" href="#heading-2-create-a-database-and-user-model">Create a database and user model</a>  </li>
<li><a class="post-section-overview" href="#3-configure-the-application-for-jwt-authorization">Configure the application for JWT authentication</a>  </li>
<li><a class="post-section-overview" href="#heading-4-create-protected-routes">Create protected routes</a>  </li>
<li><a class="post-section-overview" href="#heading-5-create-a-login-page">Create a Login Function</a></li>
<li><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></li>
</ul>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>To follow along with this tutorial you will need:</p>
<ul>
<li>An understanding of HTTP Methods</li>
<li>An understanding of how to create APIs in Flask</li>
<li>VS Code (or other similar) editor</li>
<li>A terminal</li>
</ul>
<h2 id="heading-what-is-a-json-web-token">What is a JSON Web Token?</h2>
<p>JSON Web Tokens, or JWTs, are an authentication mechanism used to securely transmit information between a client and a server in JSON format. </p>
<p>This information can be verified and trusted because it is digitally signed with the <a target="_blank" href="https://xilinx.github.io/Vitis_Libraries/security/2020.1/guide_L1/internals/hmac.html">HMAC algorithm</a> or a public/private key pair using <a target="_blank" href="https://en.wikipedia.org/wiki/RSA_(cryptosystem)">RSA</a> or <a target="_blank" href="https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm">ECDSA</a>. </p>
<p>The tokens are encoded into three parts, each divided by a period, like this:</p>
<pre><code>Header.Payload.Signature
</code></pre><ul>
<li><strong>Header:</strong> This defines the type of token (JWT) and the signing algorithm used.</li>
<li><strong>Payload:</strong> This carries user-specific data like user ID, username, roles, and any additional claims you want to include. This payload is encoded in Base64 for maximum security.</li>
<li><strong>Signature:</strong> This is a hashed combination of the header, the payload, and the server's secret key. It ensures the token's integrity and that any modifications to the token will be detected.</li>
</ul>
<h2 id="heading-how-do-jwts-work">How Do JWTs Work?</h2>
<p>To understand how JWTs work, you need to know what the tokens are meant to do. JWTs are not created to hide data but to ensure that the data being sent is authenticated. This is why the JWT is signed and encoded, not encrypted.</p>
<p>A JWT acts as a stateless means of transmitting data from a client to a server. This means that it doesn't store any session object in the browser, so the browser doesn't maintain a session state between requests. </p>
<p>Instead, JWTs use a token that is sent in a request header each time a request is made. This token confirms that the token sent is authenticated and is allowed access to make that request.  </p>
<p>Let's look at how this happens:</p>
<ol>
<li>A user attempts to log in and sends a username and password to be verified by the server.</li>
<li>The verification function carries out a check to see if there's a match in the database.</li>
<li>A JWT is then generated by the server once the user is successfully authenticated (logged in) using their information (payload), such as user ID or username, and signs it using a secret key.</li>
<li>The generated JWT is sent along as a bearer token with every request header to check if the user is authenticated to make that request.</li>
</ol>
<h2 id="heading-how-to-use-json-web-tokens-to-authenticate-flask-applications">How to Use JSON Web Tokens to Authenticate Flask Applications</h2>
<p>To demonstrate how you can implement JWT authentication in Flask, we'll create a simple application that uses JWT for handling login functions and accessing protected routes.</p>
<h3 id="heading-1-install-the-dependencies">1. Install the dependencies</h3>
<p>Run this command to install the dependencies we'll need</p>
<pre><code>pip install flask flask-bcrypt Flask-JWT-Extended
</code></pre><p>Next, make sure you import the dependencies and initialize your Flask application with this code:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> Flask, jsonify, session, request, redirect, url_for
<span class="hljs-keyword">from</span> flask_jwt_extended <span class="hljs-keyword">import</span> JWTManager, create_access_token, jwt_required, get_jwt_identity, get_jwt


app = Flask(__name__)

////WRITE MAIN CODE HERE


<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>:
    <span class="hljs-keyword">with</span> app.app_context():
        app.run(debug=<span class="hljs-literal">True</span>)
</code></pre>
<h3 id="heading-2-create-a-database-and-user-model">2. Create a database and User Model</h3>
<p>To do this, we'll use SQL-Alchemy, which is a Python SQL toolkit that makes it less complex to use SQL in Python scripts. </p>
<p>To set up SQL Alchemy in your application, follow these steps:</p>
<p>First, open your terminal or command prompt and enter the following command:</p>
<pre><code>pip install sqlalchemy
</code></pre><p>This command installs SQLAlchemy in your Python environment, making it available in your project directory.</p>
<p>Next, configure your application to make use of your preferred Database Management System (DBMS). This tutorial will use the SQlite3 DBMS as it doesn't require a separate server:</p>
<pre><code>app.config[<span class="hljs-string">'SQLALCHEMY_DATABASE_URI'</span>] = <span class="hljs-string">'sqlite:///site.db'</span>
</code></pre><p>This code snippet instructs Flask-SQLAlchemy to create and use the <code>site.db</code> file in your project directory as the SQLite database for the application.</p>
<p>Then initialize the database in your application:</p>
<pre><code>db = SQLAlchemy(app)
</code></pre><p>This instance of the database acts as a bridge between the application and the database.</p>
<p>Now create the User Model where we'll store the user's details in this tutorial:</p>
<pre><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span>(<span class="hljs-title">db</span>.<span class="hljs-title">Model</span>, <span class="hljs-title">UserMixin</span>):
    <span class="hljs-title">id</span> </span>= db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(<span class="hljs-number">20</span>), unique=True, nullable=False)
    password = db.Column(db.String(<span class="hljs-number">80</span>), nullable=False)
    is_active = db.Column(db.Boolean(), <span class="hljs-keyword">default</span>=True)
    cart = db.Column(<span class="hljs-built_in">JSON</span>, nullable=True, <span class="hljs-keyword">default</span>=list)  # Make cart nullable

    # Define the relationship between User and CartProducts
    cart_products = relationship(<span class="hljs-string">'CartProducts'</span>, backref=<span class="hljs-string">"user"</span>, lazy=<span class="hljs-string">"dynamic"</span>)
    # Define the relationship between User and Wishlists
    wishlists = db.relationship(<span class="hljs-string">'Wishlists'</span>, backref=<span class="hljs-string">'user'</span>, lazy=True)

    def __repr__(self):
        <span class="hljs-keyword">return</span> f<span class="hljs-string">'&lt;User {self.username}&gt;'</span>
</code></pre><p> <strong>Note:</strong> You can create other models using the same syntax to represent different data entities in your application.</p>
<h3 id="heading-3-configure-the-application-for-jwt-authentication">3. Configure the application for JWT Authentication</h3>
<p>To implement JWT authentication in your Flask application, import the necessary libraries and set up the appropriate configurations with this code:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> Flask, jsonify, request
<span class="hljs-keyword">from</span> flask_sqlalchemy <span class="hljs-keyword">import</span> SQLAlchemy
<span class="hljs-keyword">from</span> flask_jwt_extended <span class="hljs-keyword">import</span> JWTManager, create_access_token, jwt_required

app = Flask(__name__)

<span class="hljs-comment"># Configuration</span>
app.config[<span class="hljs-string">'SECRET_KEY'</span>] = <span class="hljs-string">'your_strong_secret_key'</span>
app.config[<span class="hljs-string">"JWT_SECRET_KEY"</span>] = <span class="hljs-string">'your_jwt_secret_key'</span>
app.config[<span class="hljs-string">'JWT_TOKEN_LOCATION'</span>] = [<span class="hljs-string">'headers'</span>]

<span class="hljs-comment"># Database Initialization</span>
db = SQLAlchemy(app)

<span class="hljs-comment"># JWT Initialization</span>
jwt = JWTManager(app)

<span class="hljs-comment"># Rest of the application code (routes, etc.)</span>
</code></pre>
<p>This code snippet imports the following components needed for our application:</p>
<ul>
<li><strong>app.config['SECRET_KEY']</strong> sets the Flask application's secret key which is used to securely sign session cookies and other security-related needs.</li>
<li><strong>app.config['JWT_SECRET_KEY']</strong> sets the secret key used to encode and decode JWTs in for Flask-JWT operations.</li>
<li><strong>app.config['JWT_TOKEN_LOCATION']</strong> specifies where the application should look for the JWT. Here it's set to look in the HTTP headers.</li>
</ul>
<p>Once we've set this up, we can create the endpoints and routes that we intend to protect.</p>
<h3 id="heading-4-create-protected-routes">4. Create protected routes</h3>
<p>Protected routes are the pages that we intend to keep hidden from unauthorized users. </p>
<p>For example, let's assume we are trying to get into a venue that's exclusive to members of a society. But a guard is securing the venue from "unauthorized users" like us. In this situation, we are the application's users, the venue is the URL we are protecting, and the guard protecting the venue is a <strong><code>@jwt_required</code></strong> decorator.</p>
<p>The <strong><code>@jwt_required</code></strong> decorator is used to protect specific routes that require authentication. This decorator will confirm that there's a JWT access token in the request headers before allowing access to the page:</p>
<pre><code class="lang-python"><span class="hljs-meta">@app.route('/get_name', methods=['GET'])</span>
<span class="hljs-meta">@jwt_required()</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_name</span>():</span>
    <span class="hljs-comment"># Extract the user ID from the JWT</span>
    user_id = get_jwt_identity()
    user = User.query.filter_by(id=user_id).first()

    <span class="hljs-comment"># Check if user exists</span>
    <span class="hljs-keyword">if</span> user:
        <span class="hljs-keyword">return</span> jsonify({<span class="hljs-string">'message'</span>: <span class="hljs-string">'User found'</span>, <span class="hljs-string">'name'</span>: user.name})
    <span class="hljs-keyword">else</span>:
        <span class="hljs-keyword">return</span> jsonify({<span class="hljs-string">'message'</span>: <span class="hljs-string">'User not found'</span>}), <span class="hljs-number">404</span>
</code></pre>
<p>In this code snippet, we created a function that returns the name of the user after authentication. If the token is missing, invalid, or expired, the request will be denied, and typically, the server will return an HTTP <strong>401</strong> Unauthorized status.</p>
<h3 id="heading-5-create-a-login-page">5. Create a Login Page</h3>
<p>In this endpoint, we'll create a function that accepts username and password credentials from the client request (for example, form data) and compares the credentials gotten from the user with the user data in the database. If there's a match, a JWT access token will be generated containing the user's information.</p>
<pre><code class="lang-python"><span class="hljs-meta">@app.route('/login', methods=['POST'])</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">login</span>():</span>
    data = request.get_json()
    username = data[<span class="hljs-string">'username'</span>]
    password = data[<span class="hljs-string">'password'</span>]
    print(<span class="hljs-string">'Received data:'</span>, username , password)

    user = User.query.filter_by(username=username).first()

    <span class="hljs-keyword">if</span> user <span class="hljs-keyword">and</span> bcrypt.check_password_hash(user.password, password):
        access_token = create_access_token(identity=user.id)
        <span class="hljs-keyword">return</span> jsonify({<span class="hljs-string">'message'</span>: <span class="hljs-string">'Login Success'</span>, <span class="hljs-string">'access_token'</span>: access_token})
    <span class="hljs-keyword">else</span>:
        <span class="hljs-keyword">return</span> jsonify({<span class="hljs-string">'message'</span>: <span class="hljs-string">'Login Failed'</span>}), <span class="hljs-number">401</span>
</code></pre>
<p>In this example, the function checks the user's credentials against the database using bcrypt for secure password verification when a POST request is received. If the credentials are valid, the server generates a JWT for the user, allowing them to access protected routes.</p>
<p>Here's an example of a React form sending a POST request to the login endpoint:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">"axios"</span>;
<span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> Footer <span class="hljs-keyword">from</span> <span class="hljs-string">"./Footer"</span>;
<span class="hljs-comment">// import "./Login.css";</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Login</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [password, setPassword] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [username, setUsername] = useState(<span class="hljs-string">""</span>);

  <span class="hljs-keyword">const</span> handleLogin = <span class="hljs-keyword">async</span> (event) =&gt; {
    event.preventDefault();
    <span class="hljs-keyword">const</span> data = {
      <span class="hljs-attr">username</span>: username,
      <span class="hljs-attr">Password</span>: password,
    };

    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> axios.post(<span class="hljs-string">"http://localhost:5000/login"</span>, {
        username,
        password,
      });
      <span class="hljs-built_in">localStorage</span>.setItem(<span class="hljs-string">"access_token"</span>, response.data.access_token);
      <span class="hljs-comment">// Redirect to protected route</span>
      alert(<span class="hljs-string">"Login successful"</span>);
    } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-built_in">console</span>.error(error);
      <span class="hljs-comment">// Display error message to user</span>
    }
  };

  <span class="hljs-keyword">const</span> handleUsernameChange = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
    setUsername(event.target.value);
  };

  <span class="hljs-keyword">const</span> handlePasswordChange = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
    setPassword(event.target.value);
  };

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

          <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">method</span>=<span class="hljs-string">"post"</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">id</span>=<span class="hljs-string">""</span>
                <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Username"</span>
                <span class="hljs-attr">name</span>=<span class="hljs-string">"username"</span>
                <span class="hljs-attr">required</span>
                <span class="hljs-attr">value</span>=<span class="hljs-string">{username}</span>
                <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleUsernameChange}</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">id</span>=<span class="hljs-string">""</span>
                <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Your email"</span>
              /&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
                <span class="hljs-attr">type</span>=<span class="hljs-string">"password"</span>
                <span class="hljs-attr">required</span>
                <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Your Password"</span>
                <span class="hljs-attr">name</span>=<span class="hljs-string">"password"</span>
                <span class="hljs-attr">value</span>=<span class="hljs-string">{password}</span>
                <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handlePasswordChange}</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">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleLogin}</span>&gt;</span>
            Log In
          <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>
  );

}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Login;
</code></pre>
<p>In this React component, we provided a login form that uses Axios to send a POST request to the login endpoint. It manages username and password inputs using React's <code>useState</code> hook and submits these values once the form is submitted. </p>
<p>If the login is successful, it stores a JWT in local Storage. This allows the client-side application to retrieve the token easily when making authenticated requests to the server.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/jwtDemo-1.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this article, we've learned how to secure APIs with JSON Web Tokens in Flask. We covered the basics of JWTs, how they work, and provided a step-by-step process for implementing this method of authentication. This included everything from installing necessary dependencies to creating user models and protecting routes. </p>
<p>You can build upon this foundation, such as by adding refresh tokens, integrating with third-party OAuth providers, or handling more complex user permissions.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Set Up Magic Link Authentication with React, Flask, and Authsignal ]]>
                </title>
                <description>
                    <![CDATA[ Authentication is the process of verifying the identity of a user or system. It ensures that only authorized individuals or systems can access certain resources or perform specific actions. Magic Link Authentication offers a simple yet secure way for... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/set-up-magic-link-authentication-with-react-flask-and-authsignal/</link>
                <guid isPermaLink="false">66ba0ec19065919bb4e84ca8</guid>
                
                    <category>
                        <![CDATA[ authentication ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Flask Framework ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ashutosh Krishna ]]>
                </dc:creator>
                <pubDate>Thu, 11 Jan 2024 18:40:41 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/01/magic-link-authsignal.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Authentication is the process of verifying the identity of a user or system. It ensures that only authorized individuals or systems can access certain resources or perform specific actions.</p>
<p>Magic Link Authentication offers a simple yet secure way for users to log in without passwords. This tutorial will walk you through the implementation of Magic Link Authentication using React for the front end, Flask for the back end, and the authentication service provided by <a target="_blank" href="https://www.authsignal.com/">Authsignal</a>.</p>
<h3 id="heading-table-of-contents">Table of Contents:</h3>
<ol>
<li><a class="post-section-overview" href="#heading-understanding-magic-link-authentication">Understanding Magic Link Authentication</a></li>
<li><a target="_blank" href="https://www.freecodecamp.org/news/set-up-magic-link-authentication-with-react-flask-and-authsignal/how-to-configure-authsignal">How to Configure Authsignal</a></li>
<li><a class="post-section-overview" href="#heading-application-flow">Application Flow</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-your-backend-server">How to Set Up Your Backend Server</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-environment-variables">How to Set Up Environment Variables</a></li>
<li><a class="post-section-overview" href="#heading-how-to-initialize-the-authsignal-client">How to Initialize the Authsignal Client</a></li>
<li><a class="post-section-overview" href="#heading-authsignal-actions">Authsignal Actions</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-the-required-routes">How to Create the Required Routes</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-a-new-frontend-react-project">How to Set Up a New Frontend React Project</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-the-components">How to Set Up the Components</a></li>
<li><a class="post-section-overview" href="#heading-how-to-run-the-application">How to Run the Application</a></li>
<li><a class="post-section-overview" href="#heading-wrapping-up">Wrapping Up</a></li>
</ol>
<h2 id="heading-understanding-magic-link-authentication">Understanding Magic Link Authentication</h2>
<p>Magic link authentication is a convenient and secure authentication method that simplifies users' login process. Instead of entering a username and password, users receive a unique link via email. This link, known as a magic link, grants them access to their account without traditional credentials.</p>
<p>One key difference between magic link authentication and authentication with email verification is the user experience. With magic link authentication, users can authenticate with just a single click. They don't need to remember or enter a password, which can be especially beneficial for users who struggle with password management or find it inconvenient to type in their credentials repeatedly.</p>
<p>While email verification adds an extra layer of security, it may require the user to remember additional credentials or go through multiple steps before accessing their account. If you're interested in learning more about email verification, you can check out my article <a target="_blank" href="https://blog.ashutoshkrris.in/how-to-set-up-email-verification-in-a-flask-app">here</a> to dive deeper into the topic.</p>
<h2 id="heading-how-to-configure-authsignal">How to Configure Authsignal</h2>
<p><a target="_blank" href="https://www.authsignal.com/">Authsignal</a> is a service that makes implementing modern authentication methods (like Magic Links and Passkeys) easier. It provides simple tools to integrate secure login methods into your web apps without hassle.</p>
<p>Before proceeding with the tutorial, you need to create an Authsignal account. To do that, you can follow these steps:</p>
<p>First, go to <a target="_blank" href="https://portal.authsignal.com/users/sign_up">authsignal.com</a> and click on "Create Free Account".</p>
<p>In the next step, create your first tenant. Choose any name for your tenant and select the data storage region.</p>
<p><img src="https://lh7-us.googleusercontent.com/PoQ1Jl8b1fNXmzruv750erSeyi4jxnVlI_QAvoHDH6-O6GVHmDQ07yd2U7WxHrYTUMCyKowll7W-Bs0dBuet9KqiF-mZuV_w8IbFO5tpYziI5M5kaO1ipWEaJPJ7dkPWTNtXyib-BE-8S5VcVtanNNc" alt="Image" width="1600" height="795" loading="lazy">
<em>Creating Tenant on Authsignal</em></p>
<p>Next, you need to configure the authenticators you want to use for your application. For example, I have enabled Email Magic Link and Authenticator App (TOTP).</p>
<p><img src="https://lh7-us.googleusercontent.com/AagTYGVbXToDeHqe4S-lFUx2qgIerUbzlUnGTv3sxZ2EyPBzfDeXNcvT-_oeQksckyhGFHX2YY6g8heKHdIz18qf2N_ejed9fJDFA_pSMzfKX3d5Tid4eDnrn7PUbEX_zVh10urhFa49Ek-eSYZJdAA" alt="Image" width="1435" height="952" loading="lazy">
<em>Configuring Authenticators</em></p>
<p>Once you have configured the authenticator, navigate to the API Keys option. Here, you will find your Secret Key, which will be necessary for implementing the authentication.</p>
<p><img src="https://lh7-us.googleusercontent.com/UJgdqGLl6IRK8sr3NOsf1BXVp7EJpSFMkxTzdRw0QNhz7DqL5fyGMn7KBotMvrp3ivZnYtw8M-fdVX-aJgNrdszRyAziVCxIAXAxb-g8r42F9ZgQFlpm9D1FYicnhuS4DcS5V7hZ430FM5ruEUioiSw" alt="Image" width="926" height="857" loading="lazy">
<em>Finding your secret key</em></p>
<h2 id="heading-application-flow">Application Flow</h2>
<p>Let's understand the flow of the application:</p>
<h3 id="heading-initial-visit">Initial Visit</h3>
<ul>
<li>The user visits the application's user interface. On the user interface, they see a login input box and a signup option. Since the user is new, they opt to sign up.</li>
</ul>
<h3 id="heading-signup-flow">Signup Flow</h3>
<ul>
<li>Upon clicking the signup link, the user is directed to a page to enter their chosen username.</li>
<li>After entering the username and clicking the signup button, the front end triggers a POST API call to /api/signup, sending the username in the request body.</li>
<li>The backend receives the request and communicates with the Authsignal server for user authentication.</li>
<li>Authsignal prompts the user to set up Magic Link authentication by entering their email address.</li>
<li>Authsignal sends a magic link to the provided email address.</li>
<li>After clicking the magic link, the user is authenticated and redirected to the home page, where they receive a welcome message displaying their email address. The page also includes a logout button.</li>
</ul>
<h3 id="heading-login-flow">Login Flow</h3>
<ul>
<li>The user logs out and returns to the login page.</li>
<li>Here, the user enters their registered username and clicks the Login button.</li>
<li>Upon clicking Login, the front end triggers a POST API call to /api/login, passing the username in the request body.</li>
<li>The backend again communicates with Authsignal for user authentication, prompting the setup of Magic Link authentication.</li>
<li>The user is directed to a page to enter their email address.</li>
<li>Authsignal sends a magic link to the provided email address.</li>
<li>After clicking the magic link, the user is authenticated and redirected to the home page, greeted with a welcome message displaying their email address.</li>
</ul>
<p>This flow ensures users can sign up using a chosen username, and set up Magic Link authentication via email for both signup and login. Here is a video tutorial to visually aid you in understanding the flow:</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/kr8frW5Wwcg" 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>
<h2 id="heading-how-to-set-up-your-backend-server">How to Set Up Your Backend Server</h2>
<p>In this section, I will guide you through how to set up your Flask server for implementing Magic Link Authentication. Before we begin, it's recommended to set up a virtual environment to isolate your project's dependencies. Here's how you can do it:</p>
<ol>
<li>Open your terminal or command prompt.</li>
<li>Navigate to your project's directory.</li>
<li>Run the following command to create a new virtual environment:</li>
</ol>
<pre><code class="lang-bash">python -m venv myenv
</code></pre>
<p>Note: Replace <code>myenv</code> with the desired name for your virtual environment.</p>
<ol start="4">
<li><p>Activate the virtual environment using the appropriate command for your operating system:</p>
</li>
<li><p>For Windows:</p>
</li>
</ol>
<pre><code class="lang-bash"><span class="hljs-built_in">source</span> myenv/Scripts/activate
</code></pre>
<ul>
<li>For macOS/Linux:</li>
</ul>
<pre><code class="lang-bash"><span class="hljs-built_in">source</span> myenv/bin/activate
</code></pre>
<p>Now that you have your virtual environment set up, let's install the necessary dependencies.</p>
<p>To begin, make sure you have Flask installed, which is a micro web framework for Python. You can install it using the following one-liner:</p>
<pre><code class="lang-bash">pip install Flask
</code></pre>
<p>Next, we need <code>python-decouple</code>, a library that helps manage configuration settings in separate files. Install it with the following command:</p>
<pre><code class="lang-bash">pip install python-decouple
</code></pre>
<p>The <code>flask-cors</code> library is a Flask extension that allows for Cross-Origin Resource Sharing (CORS) support in your Flask application.</p>
<pre><code class="lang-bash">pip install flask-cors
</code></pre>
<p>Finally, we need to install the Python SDK for Authsignal. You can install it with the following command:</p>
<pre><code class="lang-bash">pip install authsignal
</code></pre>
<p>Now that we have all the necessary dependencies installed, let's create a sample Flask server to get started with Magic Link Authentication. Here's a basic setup to help you get started:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> Flask
<span class="hljs-keyword">from</span> flask_cors <span class="hljs-keyword">import</span> CORS

app = Flask(__name__)
CORS(app, supports_credentials=<span class="hljs-literal">True</span>)

<span class="hljs-meta">@app.route("/")</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">hello</span>():</span>
    <span class="hljs-keyword">return</span> <span class="hljs-string">"Hello, world!"</span>

<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>:
    app.run(debug=<span class="hljs-literal">True</span>)
</code></pre>
<p>In the next steps, we will integrate AuthSignal and implement the Magic Link Authentication functionality into this server.</p>
<h2 id="heading-how-to-set-up-environment-variables">How to Set Up Environment Variables</h2>
<p>To successfully configure and integrate AuthSignal into your Flask server, you need to set up the following environment variables:</p>
<ul>
<li><code>AUTHSIGNAL_BASE_URL</code>: This variable contains the base URL of the Authsignal server. It allows your server to communicate with Authsignal's authentication service.</li>
<li><code>AUTHSIGNAL_SECRET_KEY</code>: This variable contains the secret key associated with your Authsignal project. It is used for secure communication between your server and AuthSignal.</li>
<li><code>SECRET_KEY</code>: This variable is a random key used to encrypt the cookies and send them to the browser.</li>
</ul>
<p>Setting environment variables instead of hardcoding in the code provides improved security by keeping sensitive information, such as API keys and secret keys, separate from the codebase. This reduces the risk of accidental exposure or unauthorized access to these credentials.</p>
<p>To set up these environment variables, you can follow these steps:</p>
<ol>
<li>Open a terminal or command prompt.</li>
<li>Navigate to the directory where your Flask server is located.</li>
<li>Create a <code>.env</code> file and export the environment variables using the following commands:</li>
</ol>
<pre><code class="lang-bash"><span class="hljs-built_in">export</span> AUTHSIGNAL_BASE_URL=&lt;base_url&gt;
<span class="hljs-built_in">export</span> AUTHSIGNAL_SECRET_KEY=&lt;secret_key&gt;
<span class="hljs-built_in">export</span> SECRET_KEY=&lt;random-secret-key&gt;
</code></pre>
<p>Make sure to replace <code>&lt;base_url&gt;</code>, <code>&lt;secret_key&gt;</code>, and <code>&lt;random-secret-key&gt;</code> with the appropriate values for your Authsignal project. You can find the values for these environment variables in the API Keys section of the Authsignal dashboard as explained earlier.</p>
<p>Note: The method for setting environment variables can vary depending on your operating system. The above commands are applicable for Unix-based systems. For Windows, you can use the <code>set</code> command instead of <code>export</code>.</p>
<p>To export the variables added in the .env file, you can use the following command in the terminal:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">source</span> .env
</code></pre>
<p>By properly setting these environment variables, your Flask server can securely communicate with Authsignal and implement the Magic Link Authentication functionality.</p>
<h2 id="heading-how-to-initialize-the-authsignal-client">How to Initialize the Authsignal Client</h2>
<p>To integrate Authsignal into your Flask server and implement Magic Link Authentication, you need to initialize the Authsignal client. Here's an example of how you can do this:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> Flask
<span class="hljs-keyword">from</span> flask_cors <span class="hljs-keyword">import</span> CORS
<span class="hljs-keyword">import</span> authsignal.client
<span class="hljs-keyword">from</span> decouple <span class="hljs-keyword">import</span> config

app = Flask(__name__)
CORS(app)

AUTHSIGNAL_BASE_URL = config(<span class="hljs-string">"AUTHSIGNAL_BASE_URL"</span>)
AUTHSIGNAL_SECRET_KEY = config(<span class="hljs-string">"AUTHSIGNAL_SECRET_KEY"</span>)
SECRET_KEY = config(<span class="hljs-string">"SECRET_KEY"</span>)

authsignal_client = authsignal.Client(
    api_key=AUTHSIGNAL_SECRET_KEY,
    api_url=AUTHSIGNAL_BASE_URL
)
</code></pre>
<p>In this code snippet, we first import the <code>authsignal.client</code>, the Python SDK for Authsignal. We also import config from python-decouple to retrieve the environment variables.</p>
<p>We retrieve the environment variables <code>AUTHSIGNAL_BASE_URL</code>, <code>AUTHSIGNAL_SECRET_KEY</code> and <code>SECRET_KEY</code> using config from python-decouple.</p>
<p>Finally, we initialize the <code>authsignal.Client</code> by passing in the API key <code>AUTHSIGNAL_SECRET_KEY</code> and the base URL of the Authsignal server <code>AUTHSIGNAL_BASE_URL</code>.</p>
<p>By initializing the Authsignal client, we are ready to implement the Magic Link Authentication functionality in our Flask server.</p>
<h2 id="heading-authsignal-actions">Authsignal Actions</h2>
<p>Authsignal allows you to create actions to track and manage user interactions in your application. Actions are events that can be triggered by users, such as signing up or logging in. By creating custom actions, you can have more control over the authentication process and implement specific authentication methods like Magic Link Authentication.</p>
<p>To create an action on your Authsignal dashboard, follow these steps:</p>
<ol>
<li>Click on "<strong>Actions</strong>" in your Authsignal dashboard.</li>
<li>Click on "<strong>Configure a new action</strong>" to create a new action.</li>
<li>Enter a name for the action that describes its purpose or the user interaction it represents.</li>
<li>Next, you can configure the rule for the action. In our case, since we want to implement Magic Link Authentication, we will add a rule to challenge users with Email Magic Link. This will send a magic link to the user's email for authentication.</li>
<li>Save the action to apply the rule and make it active.</li>
</ol>
<p>Here is a video demonstrating the process of creating an Authsignal action and configuring it for Magic Link Authentication:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/action.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Creating action on Authsignal</em></p>
<p>You can create two actions – "<strong>signUp</strong>" and "<strong>signIn</strong>". In the next steps, we will make use of these actions.</p>
<h2 id="heading-how-to-create-the-required-routes">How to Create the Required Routes</h2>
<p>Finally, to implement the Magic Link Authentication, we need to create three routes: <code>/api/signup</code>, <code>/api/login</code>, <code>/api/callback</code>, and <code>/api/user</code>.</p>
<h3 id="heading-apisignup-route"><code>/api/signup</code> Route</h3>
<p>The <code>/api/signup</code> route is responsible for allowing the users to register in our application. Here's how we implement it:</p>
<pre><code class="lang-python"><span class="hljs-meta">@app.route('/api/signup', methods=['POST'])</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">signup</span>():</span>
    username = request.json.get(<span class="hljs-string">'username'</span>)
    <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> username:
        <span class="hljs-keyword">return</span> jsonify({<span class="hljs-string">'error'</span>: <span class="hljs-string">'Missing username parameter'</span>}), <span class="hljs-number">400</span>

    response = authsignal_client.track(
        user_id=username,
        action=<span class="hljs-string">"signUp"</span>,
        payload={
            <span class="hljs-string">"user_id"</span>: username,
            <span class="hljs-string">"redirectUrl"</span>: <span class="hljs-string">"http://localhost:5000/api/callback"</span>
        }
    )
    <span class="hljs-keyword">return</span> jsonify(response), <span class="hljs-number">200</span>
</code></pre>
<p>In this implementation, the route expects a JSON payload containing the <code>username</code> parameter. It then uses the <code>authsignal_client</code> to track the user's <strong>signUp</strong> action and generate a Magic Link. The <code>track</code> method lets you record actions performed by users and initiate challenges. The <code>redirectUrl</code> specifies the URL where the user will be redirected after they have been authenticated. We will create this API next.</p>
<h3 id="heading-apicallback-route"><code>/api/callback</code> Route</h3>
<p>The <code>/api/callback</code> route handles the callback URL where the user is redirected after verifying themselves. Here's the implementation for this route:</p>
<pre><code class="lang-python"><span class="hljs-meta">@app.route('/api/callback', methods=['GET'])</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">callback</span>():</span>
    token = request.args.get(<span class="hljs-string">'token'</span>)
    challenge_response = authsignal_client.validate_challenge(token)

    <span class="hljs-keyword">if</span> challenge_response[<span class="hljs-string">"state"</span>] == <span class="hljs-string">'CHALLENGE_SUCCEEDED'</span>:
        encoded_token = jwt.encode(
            payload={<span class="hljs-string">"username"</span>: challenge_response[<span class="hljs-string">"user_id"</span>]},
            key=SECRET_KEY,
            algorithm=<span class="hljs-string">"HS256"</span>
        )
        response = redirect(<span class="hljs-string">'http://localhost:3000/'</span>)
        response.set_cookie(
            key=<span class="hljs-string">'auth-session'</span>,
            value=encoded_token,
            secure=<span class="hljs-literal">False</span>,
            path=<span class="hljs-string">'/'</span>
        )
        <span class="hljs-keyword">return</span> response

    <span class="hljs-keyword">return</span> redirect(<span class="hljs-string">"/"</span>)
</code></pre>
<p>When the users are redirected, Authsignal adds the JWT token in the URL as a token query parameter. </p>
<p>In this implementation, the route retrieves the token parameter from the query string. It then uses the <code>authsignal_client</code> to validate the challenge and check if the authentication was successful. </p>
<p>If the authentication succeeds, we encode a JSON Web Token (JWT). The token payload includes the <code>username</code> obtained from the challenge response. It uses the <code>SECRET_KEY</code> and the <em>HS256 algorithm</em> for encryption. </p>
<p>Next, the user is redirected to the home page (http://localhost:3000/), and a <code>auth-session</code> cookie is set with the encoded token for further user identification.</p>
<p>Note that the token returned from Authsignal in the redirect is not intended to be used as a session token. It just contains information about the challenge so that we can determine if the challenge was successful.</p>
<h3 id="heading-apilogin-route"><code>/api/login</code> Route</h3>
<p>The <code>/api/login</code> route is responsible for allowing the users to log into the application. Here’s the implementation for the route:</p>
<pre><code class="lang-python"><span class="hljs-meta">@app.route('/api/login', methods=['POST'])</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">login</span>():</span>
    username = request.json.get(<span class="hljs-string">'username'</span>)
    <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> username:
        <span class="hljs-keyword">return</span> jsonify({<span class="hljs-string">'error'</span>: <span class="hljs-string">'Missing username parameter'</span>}), <span class="hljs-number">400</span>

    response = authsignal_client.track(
        user_id=username,
        action=<span class="hljs-string">"signIn"</span>,
        payload={
            <span class="hljs-string">"user_id"</span>: username,
            <span class="hljs-string">"redirectUrl"</span>: <span class="hljs-string">"http://localhost:5000/api/callback"</span>
        }
    )
    <span class="hljs-keyword">return</span> jsonify(response), <span class="hljs-number">200</span>
</code></pre>
<p>The route is configured to handle POST requests on the <code>/api/login</code> endpoint. Upon receiving a POST request, the route first extracts the provided <code>username</code> from the JSON payload sent with the request. It ensures that the username is present. If not, it promptly returns a 400 error response indicating a missing username parameter.</p>
<p>Similar to the signup flow, it then uses the <code>authsignal_client</code> to track the user's <strong>signIn</strong> action and generate a Magic Link. The redirectUrl specifies the URL where the user will be redirected after they have been authenticated.</p>
<h3 id="heading-apiuser-route"><strong><code>/api/user</code> Route</strong></h3>
<p>The <code>/api/user</code> route is responsible for retrieving user information. Here's the implementation for this route:</p>
<pre><code class="lang-python"><span class="hljs-meta">@app.route("/api/user", methods=['GET'])</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">user</span>():</span>
    token = request.cookies.get(<span class="hljs-string">'auth-session'</span>)
    decoded_token = jwt.decode(token, SECRET_KEY, algorithms=[<span class="hljs-string">"HS256"</span>])
    username = decoded_token.get(<span class="hljs-string">'username'</span>)
    response = authsignal_client.get_user(user_id=username)
    <span class="hljs-keyword">return</span> jsonify({<span class="hljs-string">"username"</span>: username, <span class="hljs-string">"email"</span>: response[<span class="hljs-string">"email"</span>]}), <span class="hljs-number">200</span>
</code></pre>
<p>In this implementation, the GET endpoint starts by extracting the auth-session cookie from the incoming request. Then it decodes the JWT using the jwt.decode method, utilizing the <code>SECRET_KEY</code> as the secret key for decoding. </p>
<p>The decoded token provides the username of the user. It then uses the <code>authsignal_client</code> to retrieve user information based on the provided <code>userId</code>. It then returns a JSON response with the username and email information.</p>
<p>By implementing these routes, we will be able to handle the basic authentication process and retrieve user information in our Flask server.</p>
<h2 id="heading-how-to-set-up-a-new-frontend-react-project">How to Set Up a New Frontend React Project</h2>
<p>Let's set up our front-end project in this section. This will also include setting up routing in the application.</p>
<p>Start by initializing a new React project using <code>create-react-app</code> or any preferred method (<a target="_blank" href="https://www.freecodecamp.org/news/complete-vite-course-for-beginners/">like Vite</a>, for example, which is a more modern way to set up a React app). This command sets up the basic structure for your React application.</p>
<pre><code class="lang-bash">npx create-react-app magic-link-auth
<span class="hljs-built_in">cd</span> magic-link-auth
</code></pre>
<p>Once the project is created and you're inside the project directory, install the required dependencies. Here, we need <code>react-router-dom</code> for handling routing and <code>bootstrap</code> for easy styling.</p>
<pre><code class="lang-bash">npm install react-router-dom bootstrap
</code></pre>
<h3 id="heading-import-bootstrap-css">Import Bootstrap CSS</h3>
<p>Bootstrap provides pre-styled components and utilities for easier and faster styling of your application.</p>
<p>In the <code>index.js</code> file, import Bootstrap:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> ReactDOM <span class="hljs-keyword">from</span> <span class="hljs-string">'react-dom/client'</span>;
<span class="hljs-keyword">import</span> App <span class="hljs-keyword">from</span> <span class="hljs-string">'./App'</span>;
<span class="hljs-keyword">import</span> reportWebVitals <span class="hljs-keyword">from</span> <span class="hljs-string">'./reportWebVitals'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"bootstrap/dist/css/bootstrap.min.css"</span>; <span class="hljs-comment">// Import Bootstrap CSS</span>

<span class="hljs-keyword">const</span> root = ReactDOM.createRoot(<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'root'</span>));
root.render(
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">React.StrictMode</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">App</span> /&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">React.StrictMode</span>&gt;</span></span>
);

<span class="hljs-comment">// If you want to start measuring performance in your app, pass a function</span>
<span class="hljs-comment">// to log results (for example: reportWebVitals(console.log))</span>
<span class="hljs-comment">// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals</span>
reportWebVitals();
</code></pre>
<p>Additionally, we will write some custom CSS. Replace the code in the <code>index.css</code> file with the following code:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">html</span>,
<span class="hljs-selector-tag">body</span> {
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">font-family</span>: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
    Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
}

* {
  <span class="hljs-attribute">box-sizing</span>: border-box;
}

<span class="hljs-selector-tag">main</span> {
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">5rem</span> <span class="hljs-number">0</span>;
  <span class="hljs-attribute">flex</span>: <span class="hljs-number">1</span>;
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">flex-direction</span>: column;
  <span class="hljs-attribute">justify-content</span>: center;
  <span class="hljs-attribute">align-items</span>: center;
}

<span class="hljs-selector-tag">code</span> {
  <span class="hljs-attribute">background</span>: <span class="hljs-number">#fafafa</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">5px</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">0.75rem</span>;
  <span class="hljs-attribute">font-family</span>: Menlo, Monaco, Lucida Console, Courier New, monospace;
}

<span class="hljs-selector-tag">input</span><span class="hljs-selector-attr">[type=<span class="hljs-string">"button"</span>]</span> {
  <span class="hljs-attribute">border</span>: none;
  <span class="hljs-attribute">background</span>: cornflowerblue;
  <span class="hljs-attribute">color</span>: white;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">12px</span> <span class="hljs-number">24px</span>;
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">8px</span>;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">18px</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">8px</span>;
  <span class="hljs-attribute">cursor</span>: pointer;
}
</code></pre>
<p>Similarly, replace the code in the <code>App.css</code> with the following code:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.mainContainer</span> {
  <span class="hljs-attribute">flex-direction</span>: column;
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">justify-content</span>: center;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">100vh</span>;
}

<span class="hljs-selector-class">.titleContainer</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">flex-direction</span>: column;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">48px</span>;
  <span class="hljs-attribute">font-weight</span>: bolder;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">justify-content</span>: center;
}

<span class="hljs-selector-class">.resultContainer</span>,
<span class="hljs-selector-class">.historyItem</span> {
  <span class="hljs-attribute">flex-direction</span>: row;
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">400px</span>;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">justify-content</span>: space-between;
}

<span class="hljs-selector-class">.historyContainer</span> {
  <span class="hljs-attribute">flex-direction</span>: column;
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">200px</span>;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">flex-grow</span>: <span class="hljs-number">5</span>;
  <span class="hljs-attribute">justify-content</span>: flex-start;
}

<span class="hljs-selector-class">.buttonContainer</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">flex-direction</span>: column;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">justify-content</span>: center;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">260px</span>;
}

<span class="hljs-selector-class">.inputContainer</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">flex-direction</span>: column;
  <span class="hljs-attribute">align-items</span>: flex-start;
  <span class="hljs-attribute">justify-content</span>: center;
}

<span class="hljs-selector-class">.inputContainer</span>&gt;<span class="hljs-selector-class">.errorLabel</span> {
  <span class="hljs-attribute">color</span>: red;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">16px</span>;
  <span class="hljs-attribute">text-align</span>: center;
}

<span class="hljs-selector-class">.inputBox</span> {
  <span class="hljs-attribute">height</span>: <span class="hljs-number">48px</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">400px</span>;
  <span class="hljs-attribute">font-size</span>: medium;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">8px</span>;
  <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid grey;
  <span class="hljs-attribute">padding-left</span>: <span class="hljs-number">8px</span>;
}

<span class="hljs-selector-class">.inputButton</span> {
  <span class="hljs-attribute">height</span>: <span class="hljs-number">48px</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">400px</span>;
}
</code></pre>
<h3 id="heading-set-up-routing">Set Up Routing</h3>
<p>Routing in React applications helps navigate between different views or pages. <code>react-router-dom</code> simplifies this process.</p>
<p>In your <code>App.js</code> file, configure the routing:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { BrowserRouter, Routes, Route } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router-dom"</span>;
<span class="hljs-keyword">import</span> Dashboard <span class="hljs-keyword">from</span> <span class="hljs-string">"./pages/Dashboard"</span>;
<span class="hljs-keyword">import</span> Register <span class="hljs-keyword">from</span> <span class="hljs-string">"./pages/Register"</span>;
<span class="hljs-keyword">import</span> Login <span class="hljs-keyword">from</span> <span class="hljs-string">"./pages/Login"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./App.css"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./index.css"</span>;

<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">BrowserRouter</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Routes</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Dashboard</span> /&gt;</span>} /&gt;
        <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/login"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Login</span> /&gt;</span>} /&gt;
        <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/signup"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Register</span> /&gt;</span>} /&gt;
      <span class="hljs-tag">&lt;/<span class="hljs-name">Routes</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">BrowserRouter</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>It defines an App component that encapsulates the entire application structure within a <code>&lt;BrowserRouter&gt;</code> component. Inside <code>&lt;Routes&gt;</code>, we define three  components: one for the root path <code>/</code> rendering the <code>Dashboard</code> component, and two for the <code>/login</code> and <code>/signup</code>  paths, rendering the <code>Login</code> and <code>Register</code> components respectively. </p>
<p>This setup enables navigation between different views based on URL paths, allowing users to access specific components when they visit corresponding routes within the application.</p>
<p>In the upcoming sections, we will set up the above-mentioned three components.</p>
<h2 id="heading-how-to-set-up-the-components">How to Set Up the Components</h2>
<p>In the previous section, we imported two components from the <code>src/pages</code> folder. Let's create a <code>pages</code> folder inside the <code>src</code> folder, and then we can start creating the components.</p>
<h3 id="heading-register-component">Register Component</h3>
<p>Let’s create a <code>Register.jsx</code> file inside the pages folder. The <strong>Register</strong> component allows users to register within our application.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React, { useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { useNavigate, Link } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router-dom"</span>;

<span class="hljs-keyword">const</span> Register = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [username, setUsername] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [usernameError, setUsernameError] = useState(<span class="hljs-string">""</span>);

  <span class="hljs-keyword">const</span> navigate = useNavigate();

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> isAuthenticated = checkCookies();
    <span class="hljs-keyword">if</span> (isAuthenticated) {
      navigate(<span class="hljs-string">"/"</span>);
    }
  }, [navigate]);

  <span class="hljs-keyword">const</span> checkCookies = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> authSessionCookie = <span class="hljs-built_in">document</span>.cookie.match(<span class="hljs-string">"auth-session=([^;]+)"</span>);

    <span class="hljs-keyword">return</span> !!authSessionCookie;
  };

  <span class="hljs-keyword">const</span> onButtonClick = <span class="hljs-function">() =&gt;</span> {
    setUsernameError(<span class="hljs-string">""</span>);

    <span class="hljs-keyword">if</span> (<span class="hljs-string">""</span> === username) {
      setUsernameError(<span class="hljs-string">"Username is mandatory!"</span>);
      <span class="hljs-keyword">return</span>;
    }

    signup();
  };

  <span class="hljs-keyword">const</span> signup = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">"http://localhost:5000/api/login"</span>, {
      <span class="hljs-attr">method</span>: <span class="hljs-string">"POST"</span>,
      <span class="hljs-attr">headers</span>: {
        <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/json"</span>,
      },
      <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify({
        username,
      }),
      <span class="hljs-attr">credentials</span>: <span class="hljs-string">"include"</span>,
    });

    <span class="hljs-keyword">const</span> { url } = <span class="hljs-keyword">await</span> response.json();

    <span class="hljs-comment">// Redirect to verification URL</span>
    <span class="hljs-built_in">window</span>.location.href = url;
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>"<span class="hljs-attr">mainContainer</span>"}&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>"<span class="hljs-attr">titleContainer</span>"}&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Sign Up<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">br</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>"<span class="hljs-attr">inputContainer</span>"}&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
          <span class="hljs-attr">value</span>=<span class="hljs-string">{username}</span>
          <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Enter your username"</span>
          <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setUsername(e.target.value)}
          className={"inputBox"}
        /&gt;
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"errorLabel text-center"</span>&gt;</span>{usernameError}<span class="hljs-tag">&lt;/<span class="hljs-name">label</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">br</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>"<span class="hljs-attr">inputContainer</span>"}&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
          <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>"<span class="hljs-attr">inputButton</span>"}
          <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span>
          <span class="hljs-attr">onClick</span>=<span class="hljs-string">{onButtonClick}</span>
          <span class="hljs-attr">value</span>=<span class="hljs-string">{</span>"<span class="hljs-attr">Sign</span> <span class="hljs-attr">Up</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>
        Existing User? <span class="hljs-tag">&lt;<span class="hljs-name">Link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/login"</span>&gt;</span>Login here<span class="hljs-tag">&lt;/<span class="hljs-name">Link</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></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Register;
</code></pre>
<p>The component initializes state variables using <code>useState</code> to manage the visibility of the <code>usernameError</code> and store the username input in <code>userName</code>. It also initializes the <code>navigate</code> function from <code>useNavigate</code> to handle navigation within the application.</p>
<p>We use the <code>useEffect</code> hook to check for authentication cookies when the component mounts. It calls the <code>checkCookies</code> function, which checks for the existence of cookies that we had set from the backend server. If <code>auth-session</code> cookie is found, the user is automatically redirected to the root URL using navigate("/").</p>
<p>Clicking the “Sign Up” button triggers the <code>onButtonClick</code> function. It first checks whether the user has entered the username. If not, it shows an error message using the <code>usernameError</code>. If the user has entered the username, it calls the <code>signup</code> function.</p>
<p>The <code>signup</code> performs an asynchronous POST request to the <code>/api/signup</code> endpoint with the provided username. Upon successful response, it redirects the user to the received verification URL by changing window.location.href.</p>
<p>The JSX returned by the component defines the UI layout that looks like the below:</p>
<p><img src="https://lh7-us.googleusercontent.com/gncsDRe9QVK20DWMkiWwdGOt_ZymbSVXTv-8UGvyKIpp5-TZ64-DwLGLbMtDM0B-wgXh8jNOCdkA0kia3-gJftMxFaH-za_4O0cqCSvK9GLMHSbO_nH_UfgGIf5QhHaOZg559_N0c4P9Oof4O5JmkPE" alt="Image" width="1600" height="796" loading="lazy">
<em>Register UI Component</em></p>
<p>It includes an input field for the users to enter their username and a "Sign Up" button. Below the button, we have a link to the Login page for the existing users to log in.</p>
<h3 id="heading-login-component">Login Component</h3>
<p>We have kept the login page similar to the signup page for simplicity. Hence, the Login component is pretty much the same as the Register component.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React, { useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { useNavigate, Link } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router-dom"</span>;

<span class="hljs-keyword">const</span> Login = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [username, setUsername] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [usernameError, setUsernameError] = useState(<span class="hljs-string">""</span>);

  <span class="hljs-keyword">const</span> navigate = useNavigate();

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> isAuthenticated = checkCookies();
    <span class="hljs-keyword">if</span> (isAuthenticated) {
      navigate(<span class="hljs-string">"/"</span>);
    }
  }, [navigate]);

  <span class="hljs-keyword">const</span> checkCookies = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> authSessionCookie = <span class="hljs-built_in">document</span>.cookie.match(<span class="hljs-string">"auth-session=([^;]+)"</span>);

    <span class="hljs-keyword">return</span> !!authSessionCookie;
  };

  <span class="hljs-keyword">const</span> onButtonClick = <span class="hljs-function">() =&gt;</span> {
    setUsernameError(<span class="hljs-string">""</span>);

    <span class="hljs-keyword">if</span> (<span class="hljs-string">""</span> === username) {
      setUsernameError(<span class="hljs-string">"Username is mandatory!"</span>);
      <span class="hljs-keyword">return</span>;
    }

    login();
  };

  <span class="hljs-keyword">const</span> login = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">"http://localhost:5000/api/login"</span>, {
      <span class="hljs-attr">method</span>: <span class="hljs-string">"POST"</span>,
      <span class="hljs-attr">headers</span>: {
        <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/json"</span>,
      },
      <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify({
        username,
      }),
      <span class="hljs-attr">credentials</span>: <span class="hljs-string">"include"</span>,
    });

    <span class="hljs-keyword">const</span> { url } = <span class="hljs-keyword">await</span> response.json();

    <span class="hljs-comment">// Redirect to verification URL</span>
    <span class="hljs-built_in">window</span>.location.href = url;
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>"<span class="hljs-attr">mainContainer</span>"}&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>"<span class="hljs-attr">titleContainer</span>"}&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Login<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">br</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>"<span class="hljs-attr">inputContainer</span>"}&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
          <span class="hljs-attr">value</span>=<span class="hljs-string">{username}</span>
          <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Enter your username"</span>
          <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(ev)</span> =&gt;</span> setUsername(ev.target.value)}
          className={"inputBox"}
        /&gt;
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"errorLabel text-center"</span>&gt;</span>{usernameError}<span class="hljs-tag">&lt;/<span class="hljs-name">label</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">br</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>"<span class="hljs-attr">inputContainer</span>"}&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
          <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>"<span class="hljs-attr">inputButton</span>"}
          <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span>
          <span class="hljs-attr">onClick</span>=<span class="hljs-string">{onButtonClick}</span>
          <span class="hljs-attr">value</span>=<span class="hljs-string">{</span>"<span class="hljs-attr">Log</span> <span class="hljs-attr">in</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>
        New User? <span class="hljs-tag">&lt;<span class="hljs-name">Link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/signup"</span>&gt;</span>Sign up here<span class="hljs-tag">&lt;/<span class="hljs-name">Link</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></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Login;
</code></pre>
<p>The only significant difference other than the text and button in the UI here is that we will be making the API call to the <code>/api/login</code> route when the users hit the Login button.</p>
<p>The UI looks like below:</p>
<p><img src="https://lh7-us.googleusercontent.com/F4EDOhuMbTRtXt3UxhpLYdZPT8XtCuYWjEX3H95bEXEZatLDsuRxaut3KZ3ZtyHSWIQ1WkuA5WWUxZcXrCBHyCMfMG-LQTKjnQHXyY8Y2Ha93YstE0Kycd9ji9lj33wMc1D8Km7pFNu5EGyQh14D9m8" alt="Image" width="1600" height="798" loading="lazy">
<em>Login UI Component</em></p>
<h3 id="heading-dashboard-component">Dashboard Component</h3>
<p>The Dashboard component in our application serves as the interface for authenticated users, displaying a welcome message with the user’s email and enabling user logout functionality. </p>
<p>Let’s create a <code>Dashboard.jsx</code> file inside the <code>pages</code> folder.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React, { useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { useNavigate } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router-dom"</span>;

<span class="hljs-keyword">const</span> Dashboard = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [userEmail, setUserEmail] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> navigate = useNavigate();

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> checkCookies = <span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-keyword">const</span> authSessionCookie = <span class="hljs-built_in">document</span>.cookie.match(<span class="hljs-string">"auth-session=([^;]+)"</span>);

      <span class="hljs-keyword">if</span> (!authSessionCookie) {
        navigate(<span class="hljs-string">"/auth"</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>;
    };

    <span class="hljs-keyword">const</span> fetchData = <span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-keyword">const</span> cookiesValid = <span class="hljs-keyword">await</span> checkCookies();
      <span class="hljs-keyword">if</span> (!cookiesValid) <span class="hljs-keyword">return</span>;

      <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">"http://localhost:5000/api/user"</span>, {
          <span class="hljs-attr">method</span>: <span class="hljs-string">"GET"</span>,
          <span class="hljs-attr">headers</span>: {
            <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/json"</span>,
          },
          <span class="hljs-attr">credentials</span>: <span class="hljs-string">"include"</span>
        });

        <span class="hljs-keyword">if</span> (!response.ok) {
          <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">"Failed to fetch user data"</span>);
        }

        <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> response.json();
        setUserEmail(data.email);
      } <span class="hljs-keyword">catch</span> (error) {
        navigate(<span class="hljs-string">"/auth"</span>);
      }
    };

    fetchData();
  }, [navigate]);

  <span class="hljs-keyword">const</span> handleLogout = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">document</span>.cookie = <span class="hljs-string">`auth-session=; max-age=0`</span>;
    navigate(<span class="hljs-string">"/auth"</span>);
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"d-flex justify-content-center align-items-center vh-100"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">main</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"px-3 text-center"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Welcome Home!<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"lead"</span>&gt;</span>You're logged in as {userEmail}!<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"d-flex justify-content-center"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">"btn btn-lg btn-dark fw-bold border-white bg-dark"</span>
            <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleLogout}</span>
          &gt;</span>
            Log Out
          <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">main</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Dashboard;
</code></pre>
<p>Upon component mounting or when <code>navigate</code> changes (a dependency of <code>useEffect</code>), the effect runs. It begins by defining two asynchronous functions. The first, <code>checkCookies</code>, verifies the presence of <code>auth-session</code> cookies. If it is missing, it redirects the user to the authentication route.</p>
<p>The second function, <code>fetchData</code>, is responsible for fetching user data. It checks the validity of cookies using <code>checkCookies</code>. Upon verification, it sends a GET request to our back-end API endpoint. Upon successful response, it updates the <code>userEmail</code> state with the user's email fetched from the API data. </p>
<p>If any error occurs during this process, such as failing to fetch user data, it redirects the user back to the authentication route.</p>
<p>The JSX returned by the component renders a simple dashboard layout.</p>
<p><img src="https://lh7-us.googleusercontent.com/ca-epjkteyLzE_dVbbWN6bC5fMVogCJLRvR8Milfjl7UzoHRK7462_YJZhkJvhoTpBtD0sNFwpGbNaLTKNEuBg6wKSxv6j5-ApmjpOtPgx-UkeM8i39A0KwAuU3L2TeRc8R_3aXugnAMcH4iGrlBP0M" alt="Image" width="1600" height="797" loading="lazy">
<em>Dashboard UI Component</em></p>
<p>The displayed content includes a welcoming message and the currently logged-in user's email. There's also a "Log Out" button which, upon clicking, initiates the logout process by triggering the <code>handleLogout</code> function. It removes the <code>auth-session</code> cookies by setting their max-age to 0, effectively expiring them. Afterward, it redirects the user to the authentication route.</p>
<h2 id="heading-how-to-run-the-application">How to Run the Application</h2>
<p>You can find the code of the final application in this <a target="_blank" href="https://github.com/ashutoshkrris/authsignal-magic-link-demo">GitHub repository</a>. To run your backend application, run <code>python app.py</code> from your back-end folder in your terminal. This will start your back-end server on port 5000. Next, run the frontend application using the <code>npm start</code> command. This will start your frontend application on the port 3000.</p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>In this tutorial, you learned how to use Authsignal to implement basic user authentication with email verification through magic links. </p>
<p>Authsignal makes handling users and keeping things safe easier, letting developers focus on improving apps. It also removes the overhead of remembering another password for the users of the application.</p>
<p>To learn more about Authsignal, <a target="_blank" href="https://docs.authsignal.com/">visit the Authsignal documentation</a>.</p>
<p>Should you have any issues or questions related to the tutorial, then feel free to reach out to me on <a target="_blank" href="https://twitter.com/ashutoshkrris">Twitter</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <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 Use an Email Validation Service for Flask User Authentication ]]>
                </title>
                <description>
                    <![CDATA[ In today's digital world, online security is really important, and user authentication is a key aspect of it.  Email-based authentication is one of the most popular and widely used methods for user registration and login. But it's not always reliable... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-email-validation-api-for-flask-user-authentication/</link>
                <guid isPermaLink="false">66ba0ea5228e16bed602a896</guid>
                
                    <category>
                        <![CDATA[ authentication ]]>
                    </category>
                
                    <category>
                        <![CDATA[ email ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Flask Framework ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ashutosh Krishna ]]>
                </dc:creator>
                <pubDate>Thu, 30 Mar 2023 22:22:39 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/03/email-validation-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In today's digital world, online security is really important, and user authentication is a key aspect of it. </p>
<p><a target="_blank" href="https://ashutoshkrris.hashnode.dev/how-to-set-up-email-verification-in-a-flask-app">Email-based authentication</a> is one of the most popular and widely used methods for user registration and login. But it's not always reliable, as users can enter fake or invalid email addresses during registration. This can lead to security risks and fraud. This is where Email Validation Services come in handy.</p>
<p>In this tutorial, you'll use the <a target="_blank" href="https://emailvalidation.io/">Email Validation Service</a> to help you automate your email validation process during user registration by validating contact information. </p>
<p>The API checks the syntax, domain, and mailbox of an email address, and can even detect disposable and risky emails. </p>
<p>By integrating this API with your application, you can ensure that only valid and genuine email addresses are used for user registration, which will enhance the security of your application.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Before you get started with the tutorial, make sure you have satisfied the following requirements:</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>, <a target="_blank" href="https://ashutoshkrris.hashnode.dev/how-to-use-blueprints-to-organize-your-flask-apps">Flask Blueprints</a> and <a target="_blank" href="https://blog.ashutoshkrris.in/how-to-interact-with-web-services-using-python">Requests</a>.</li>
</ul>
<h2 id="heading-how-to-set-up-the-virtual-environment">How to Set Up the Virtual Environment</h2>
<p>Before you start coding, you'll need to make sure you have all the necessary tools and libraries installed. To ensure that you have a clean and isolated environment, you'll create a virtual environment using <code>venv</code>.</p>
<p>Create a project directory and navigate to it in the terminal:</p>
<pre><code class="lang-bash">mkdir email-validation
<span class="hljs-built_in">cd</span> email-validation
</code></pre>
<p>Create a virtual environment named <code>env</code> using the following command:</p>
<pre><code class="lang-bash">python -m venv env
</code></pre>
<p>Python now ships with pre-installed <code>venv</code> library to create virtual environments.</p>
<p>Activate the virtual environment like this:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">source</span> env/bin/activate
</code></pre>
<p>Note: If you're on Windows, you'll need to use <code>source env/Scripts/activate</code> to activate the environment.</p>
<p>You should see <code>(env)</code> in your terminal prompt, indicating that the virtual environment has been activated.</p>
<h2 id="heading-how-email-validation-service-works">How Email Validation Service Works</h2>
<p>Email validation is an essential process for any web application that requires user authentication, and there are various ways to perform it. </p>
<p>One way is to use an email validation service such as <a target="_blank" href="https://emailvalidation.io/">emailvalidation.io</a>. This API allows developers to validate email addresses by checking whether they are syntactically correct, whether the domain exists, and whether the mailbox can receive messages.</p>
<p>The API offers a range of <a target="_blank" href="https://emailvalidation.io/pricing/">pricing plans</a> to suit different needs. The free plan allows developers to validate up to 100 emails, which should be sufficient for our testing purposes. The paid plans start at $9.99 per month and offer more requests, more features, and faster response times.</p>
<p>In this section, you'll write a Python function that sends a GET request to the API's endpoint and passes the email address to be validated as a parameter. </p>
<p>To authenticate the API request, you will also need to pass the API key with the request. Before proceeding, you must create an account on emailvalidation.io to obtain an API key. Once you've created your account, you will be redirected to a dashboard, similar to the one shown below. The API key is located in the black highlighted area.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/Screenshot-2023-03-29-112311.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>To make a GET request, you'll need to install the <code>requests</code> library in your virtual environment:</p>
<pre><code class="lang-bash">pip install requests
</code></pre>
<p>Next, create a <code>test.py</code> file and add the following code there:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> requests
<span class="hljs-keyword">from</span> requests.structures <span class="hljs-keyword">import</span> CaseInsensitiveDict


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">is_valid</span>(<span class="hljs-params">email: str</span>):</span>
    url = <span class="hljs-string">f"https://api.emailvalidation.io/v1/info?email=<span class="hljs-subst">{email}</span>"</span>

    headers = CaseInsensitiveDict()
    headers[<span class="hljs-string">"apikey"</span>] = <span class="hljs-string">"your-api-key-here"</span>

    response = requests.get(url, headers=headers)

    <span class="hljs-keyword">return</span> response.json()


print(is_valid(<span class="hljs-string">"support@emailvalidation.io"</span>))
print(is_valid(<span class="hljs-string">"venip42579@jdsdhak.com"</span>))
</code></pre>
<p>The <code>is_valid</code> function takes an email address as an argument and constructs a URL with the email address to call the emailvalidation.io API. The <code>CaseInsensitiveDict</code> class from the <code>requests.structures</code> module is used to create a dictionary with case-insensitive keys to set the API key in the header of the request. You then return the JSON response from the function.</p>
<p>Finally, you call the <code>is_valid</code> function twice with different email addresses to demonstrate how the function can validate both a valid email address (<code>support@emailvalidation.io</code>) and an invalid email address (<code>venip42579@jdsdhak.com</code>).</p>
<p>Output:</p>
<pre><code class="lang-bash">{
   <span class="hljs-string">"email"</span>:<span class="hljs-string">"support@emailvalidation.io"</span>,
   <span class="hljs-string">"user"</span>:<span class="hljs-string">"support"</span>,
   <span class="hljs-string">"tag"</span>:<span class="hljs-string">""</span>,
   <span class="hljs-string">"domain"</span>:<span class="hljs-string">"emailvalidation.io"</span>,
   <span class="hljs-string">"smtp_check"</span>:<span class="hljs-literal">true</span>,
   <span class="hljs-string">"mx_found"</span>:<span class="hljs-literal">true</span>,
   <span class="hljs-string">"did_you_mean"</span>:<span class="hljs-string">""</span>,
   <span class="hljs-string">"role"</span>:<span class="hljs-literal">true</span>,
   <span class="hljs-string">"disposable"</span>:<span class="hljs-literal">false</span>,
   <span class="hljs-string">"score"</span>:0.64,
   <span class="hljs-string">"state"</span>:<span class="hljs-string">"deliverable"</span>,
   <span class="hljs-string">"reason"</span>:<span class="hljs-string">"valid_mailbox"</span>,
   <span class="hljs-string">"free"</span>:<span class="hljs-literal">false</span>,
   <span class="hljs-string">"format_valid"</span>:<span class="hljs-literal">true</span>,
   <span class="hljs-string">"catch_all"</span>:<span class="hljs-string">"None"</span>
}
{
   <span class="hljs-string">"email"</span>:<span class="hljs-string">"venip42579@jdsdhak.com"</span>,
   <span class="hljs-string">"user"</span>:<span class="hljs-string">"venip42579"</span>,
   <span class="hljs-string">"tag"</span>:<span class="hljs-string">""</span>,
   <span class="hljs-string">"domain"</span>:<span class="hljs-string">"jdsdhak.com"</span>,
   <span class="hljs-string">"smtp_check"</span>:<span class="hljs-literal">false</span>,
   <span class="hljs-string">"mx_found"</span>:<span class="hljs-literal">false</span>,
   <span class="hljs-string">"did_you_mean"</span>:<span class="hljs-string">""</span>,
   <span class="hljs-string">"role"</span>:<span class="hljs-literal">false</span>,
   <span class="hljs-string">"disposable"</span>:<span class="hljs-literal">false</span>,
   <span class="hljs-string">"score"</span>:0.64,
   <span class="hljs-string">"state"</span>:<span class="hljs-string">"undeliverable"</span>,
   <span class="hljs-string">"reason"</span>:<span class="hljs-string">"invalid_mx"</span>,
   <span class="hljs-string">"free"</span>:<span class="hljs-literal">false</span>,
   <span class="hljs-string">"format_valid"</span>:<span class="hljs-literal">true</span>,
   <span class="hljs-string">"catch_all"</span>:<span class="hljs-string">"None"</span>
}
</code></pre>
<p>You can learn about the different keys in the response <a target="_blank" href="https://emailvalidation.io/docs/info#sample-response">here</a>. To determine if an email address is valid or invalid based on the JSON response from emailvalidation.io, you should check the following fields:</p>
<ol>
<li><code>format_valid</code>: If <code>true</code>, the email address is properly formatted. If <code>false</code>, the email address is not valid.</li>
<li><code>mx_found</code>: If <code>true</code>, at least one MX record was found for the domain. If <code>false</code>, the domain is not valid.</li>
<li><code>smtp_check</code>: If <code>true</code>, the email address has a valid mailbox. If <code>false</code>, the mailbox is not valid.</li>
<li><code>state</code>: The current state of the email address. The values can be "deliverable" or "undeliverable".</li>
</ol>
<p>Thus, you can modify the <code>is_valid</code> function to return a Boolean response instead of a JSON object as below:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> requests
<span class="hljs-keyword">from</span> requests.structures <span class="hljs-keyword">import</span> CaseInsensitiveDict


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">is_valid</span>(<span class="hljs-params">email: str</span>):</span>
    url = <span class="hljs-string">f"https://api.emailvalidation.io/v1/info?email=<span class="hljs-subst">{email}</span>"</span>

    headers = CaseInsensitiveDict()
    headers[<span class="hljs-string">"apikey"</span>] = <span class="hljs-string">"nUH1hmV24lEwX1TIXmsgRPRRZw0L0NuOeHrdMp78"</span>

    response = requests.get(url, headers=headers)
    <span class="hljs-keyword">if</span> response.status_code == <span class="hljs-number">200</span>:
        json_resp = response.json()
        format_valid = json_resp[<span class="hljs-string">"format_valid"</span>]
        mx_found = json_resp[<span class="hljs-string">"mx_found"</span>]
        smtp_check = json_resp[<span class="hljs-string">"smtp_check"</span>]
        state = json_resp[<span class="hljs-string">"state"</span>]

        <span class="hljs-keyword">return</span> format_valid <span class="hljs-keyword">and</span> mx_found <span class="hljs-keyword">and</span> smtp_check <span class="hljs-keyword">and</span> state == <span class="hljs-string">"deliverable"</span>

    <span class="hljs-keyword">return</span> <span class="hljs-literal">False</span>


print(is_valid(<span class="hljs-string">"support@emailvalidation.io"</span>))
print(is_valid(<span class="hljs-string">"venip42579@jdsdhak.com"</span>))
</code></pre>
<p>Output:</p>
<pre><code class="lang-bash">True
False
</code></pre>
<p>In the upcoming section, you'll use this function to validate emails during user registration.</p>
<h2 id="heading-how-to-set-up-basic-user-authentication-in-flask">How to Set Up Basic User Authentication in Flask</h2>
<p>In this section, you will go through the steps to set up basic user authentication in Flask. You will be using the code from <a target="_blank" href="https://blog.ashutoshkrris.in/how-to-set-up-basic-user-authentication-in-a-flask-app">one of my previous articles</a> where I had explained how to implement basic user authentication. </p>
<p>You can start by pulling the code from the GitHub repository to the <code>email-validation</code> folder:</p>
<pre><code class="lang-bash">git init
git remote add origin https://github.com/ashutoshkrris/Flask-User-Authentication.git
git pull origin main
</code></pre>
<p>Note: The command <code>git clone [https://github.com/ashutoshkrris/Flask-User-Authentication.git](https://github.com/ashutoshkrris/Flask-User-Authentication.git) .</code> won't run in this case because your directory is not empty.</p>
<p>Next, you'll see a <code>requirements.txt</code> file that contains the dependencies to run the the application in your system. Install the dependencies using the command:</p>
<pre><code class="lang-bash">pip install -r requirements.txt
</code></pre>
<p>Once all the dependencies are installed, you'll need to add the environment variables required for the project. The project contains a <code>.env</code> file which has all the environment variables. 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, you have to create the database. Since the project uses Flask-Migrate, creating the database is a fairly simple task using the following commands:</p>
<pre><code class="lang-bash">python manage.py db init
python manage.py db migrate
python manage.py db upgrade
</code></pre>
<p>Now, you can run the application using the command:</p>
<pre><code class="lang-bash">python manage.py run
</code></pre>
<p>The application will start running and you can go to <code>http://localhost:5000/login</code> in your web browser to see the application.</p>
<p>Here's a demo video that shows the application:</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/XxSESg89xEI" 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>Inside your project <code>flask-validation</code>, you'll have a <code>src</code> folder containing your source code and a <code>tests</code> folder containing the unit tests. </p>
<p>In addition to these, you'll also have a <code>config.py</code> file that contains the configuration settings for your application and a <code>manage.py</code> file that uses Flask-CLI to add different commands for running and testing your application. You'll also find other files such as <code>.env</code> and <code>requirements.txt</code> which you already know about.</p>
<p>The <code>src</code> folder contains four subfolders – <code>accounts</code>, <code>core</code>, <code>templates</code>, and <code>static</code>. The <code>templates</code> and <code>static</code> folders contain the HTML files and static files such as CSS, images, and JavaScript files, respectively. The other two folders, <code>accounts</code> and <code>core</code>, use the concept of <a target="_blank" href="https://blog.ashutoshkrris.in/how-to-use-blueprints-to-organize-your-flask-apps">Flask Blueprints</a> and contain the respective codes for different parts of the application.</p>
<p>If you want to learn more about the implementation of your Flask application, you can refer to <a target="_blank" href="https://blog.ashutoshkrris.in/how-to-set-up-basic-user-authentication-in-a-flask-app">this tutorial</a>.</p>
<h2 id="heading-how-to-integrate-the-email-validation-service-in-your-flask-app">How to Integrate the Email Validation Service in Your Flask App</h2>
<p>Up until this point, it is possible to successfully register in the application using any email address, regardless of whether it is valid or not. </p>
<p>But it's not desirable to have random or incorrect email addresses cluttering up your database. So it's a good idea to validate the email address before registering the user. If the email address is valid, you can proceed with registering the user successfully.</p>
<p>Add your Email Validation API Key in the <code>.env</code> file to so that you can read it without exposing to the public:</p>
<pre><code><span class="hljs-keyword">export</span> SECRET_KEY=fdkjshfhjsdfdskfdsfdcbsjdkfdsdf
<span class="hljs-keyword">export</span> DEBUG=True
<span class="hljs-keyword">export</span> APP_SETTINGS=config.DevelopmentConfig
<span class="hljs-keyword">export</span> DATABASE_URL=sqlite:<span class="hljs-comment">///db.sqlite</span>
<span class="hljs-keyword">export</span> FLASK_APP=src
<span class="hljs-keyword">export</span> FLASK_DEBUG=<span class="hljs-number">1</span>
<span class="hljs-keyword">export</span> API_KEY=your-api-key-here
</code></pre><p>Replace the <code>your-api-key-here</code> with your correct API key. Next, you'll again need to run the following command to export the environment variables:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">source</span> .env
</code></pre>
<p>Now, create a <code>utils.py</code> file inside the <code>accounts</code> subfolder in the <code>src</code> folder. The file will contain the utility function to validate the email. Add the following code in the file:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> requests
<span class="hljs-keyword">from</span> requests.structures <span class="hljs-keyword">import</span> CaseInsensitiveDict
<span class="hljs-keyword">from</span> decouple <span class="hljs-keyword">import</span> config


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">is_valid</span>(<span class="hljs-params">email: str</span>):</span>
    url = <span class="hljs-string">f"https://api.emailvalidation.io/v1/info?email=<span class="hljs-subst">{email}</span>"</span>

    headers = CaseInsensitiveDict()
    headers[<span class="hljs-string">"apikey"</span>] = config(<span class="hljs-string">"API_KEY"</span>)

    response = requests.get(url, headers=headers)
    <span class="hljs-keyword">if</span> response.status_code == <span class="hljs-number">200</span>:
        json_resp = response.json()
        format_valid = json_resp[<span class="hljs-string">"format_valid"</span>]
        mx_found = json_resp[<span class="hljs-string">"mx_found"</span>]
        smtp_check = json_resp[<span class="hljs-string">"smtp_check"</span>]
        state = json_resp[<span class="hljs-string">"state"</span>]

        <span class="hljs-keyword">return</span> format_valid <span class="hljs-keyword">and</span> mx_found <span class="hljs-keyword">and</span> smtp_check <span class="hljs-keyword">and</span> state == <span class="hljs-string">"deliverable"</span>

    <span class="hljs-keyword">return</span> <span class="hljs-literal">False</span>
</code></pre>
<p>As previously mentioned, the <code>is_valid()</code> function returns a Boolean value indicating whether an email address is valid or not. It's important to note that the function doesn't hardcode the API key value, instead it retrieves it from the environment variables.</p>
<p>Next, in the <code>RegisterForm</code> class in the <code>forms.py</code> file, you have a <code>validate</code> method. This method is responsible for validating the input data submitted by the user during the registration process. </p>
<p>Previously, this method only checked if the email was already registered and if the passwords matched. But you can now add an additional validation to check if the email is valid. Thus the modified <code>validate</code> method looks like this:</p>
<pre><code class="lang-python">...

<span class="hljs-keyword">from</span> src.accounts.utils <span class="hljs-keyword">import</span> is_valid

...

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">RegisterForm</span>(<span class="hljs-params">FlaskForm</span>):</span>
    ...

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">validate</span>(<span class="hljs-params">self</span>):</span>
        initial_validation = super(RegisterForm, self).validate()
        <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>
        <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> is_valid(self.email.data):
            self.email.errors.append(<span class="hljs-string">"Email is invalid"</span>)
            <span class="hljs-keyword">return</span> <span class="hljs-literal">False</span>
        user = User.query.filter_by(email=self.email.data).first()
        <span class="hljs-keyword">if</span> user:
            self.email.errors.append(<span class="hljs-string">"Email 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>In the <code>validate</code> method, if the <code>self.email.data</code> (that is the user's email address) is not valid, you append an error message to the <code>self.email.errors</code> list and return <code>False</code> which means the user data is not valid.</p>
<p>Now, when you run the application and try to register, you can see it live. Here's a demo showing both valid and invalid cases.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/03/Validation-Demo-Made-with-Clipchamp.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-other-use-cases-of-an-email-validation-service">Other Use Cases of an Email Validation Service</h2>
<p>Apart from validating a user's email during registration, there are several other use cases for Email Validation Services. Some of these are:</p>
<ol>
<li>Cleaning Email Lists: you can use email validation services to clean email lists by removing invalid, non-existent or risky email addresses. This can help to improve email deliverability and ensure that your emails reach the intended recipients.</li>
<li>Preventing Fraudulent Activities: you can also use email validation services to detect fraudulent activities such as fake account creation or fraudulent orders. By validating the email addresses associated with these activities, you can prevent such activities from happening.</li>
<li>Enhancing marketing campaigns: these services can also help improve the accuracy and effectiveness of email marketing campaigns. By ensuring that email addresses are valid and active, businesses can increase their email deliverability rates and improve their overall campaign performance.</li>
</ol>
<p>Overall, email validation services can be a powerful tool in ensuring the accuracy and validity of user data, preventing fraud, and improving the user experience.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Email validation services are a powerful tool for any application that requires verifying user email addresses. It is essential to ensure that email addresses are valid to prevent errors and to ensure that the user input data is correct. </p>
<p>In this article, you saw how to use the <a target="_blank" href="https://emailvalidation.io/">emailvalidation.io</a> API to validate an email address in Python. You also learned other potential use cases for email validation services, such as fraud detection and email marketing. </p>
<p>By implementing email validation services in your application, you can improve your user experience and ensure that your data is accurate and up-to-date.</p>
<h3 id="heading-additional-resources">Additional Resources</h3>
<ul>
<li><a target="_blank" href="https://blog.ashutoshkrris.in/how-to-use-blueprints-to-organize-your-flask-apps">How to Use Blueprints to Organize Your Flask Apps</a></li>
<li><a target="_blank" href="https://blog.ashutoshkrris.in/how-to-set-up-email-verification-in-a-flask-app">How to Set Up Email Verification in a Flask App</a></li>
<li><a target="_blank" href="https://emailvalidation.io/docs/">emailvalidation.io Documentation</a></li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Develop Database-Driven Web Apps with Python, Flask, and MySQL ]]>
                </title>
                <description>
                    <![CDATA[ Are you ready to take your web development skills to the next level? Do you want to learn how to build dynamic database-driven web applications with Python, Flask, and MySQL?  We just published a comprehensive video course on the freeCodeCamp.org You... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/develop-database-driven-web-apps-with-python-flask-and-mysql/</link>
                <guid isPermaLink="false">66b2020e82069b4c678c98ad</guid>
                
                    <category>
                        <![CDATA[ Flask Framework ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                    <category>
                        <![CDATA[ youtube ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Beau Carnes ]]>
                </dc:creator>
                <pubDate>Thu, 16 Feb 2023 14:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/02/pyweb.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Are you ready to take your web development skills to the next level? Do you want to learn how to build dynamic database-driven web applications with Python, Flask, and MySQL? </p>
<p>We just published a comprehensive video course on the freeCodeCamp.org YouTube channel that is designed to teach you how to build and deploy a production-ready database-driven web application using Python and Flask.</p>
<p>Akash created this course. He is the CEO of Jovian and he has created many popular courses.</p>
<p>The course is divided into two parts, each with its own set of objectives, covering everything from Flask basics to MySQL database setup, and application deployment.</p>
<p>In Part 1, you will learn how to build and deploy a site using the Flask Python web framework. You will start by creating a "Jovian Careers" website that lists job openings at Jovian.</p>
<p>You will also learn how to use a modern HTML &amp; CSS framework for layout and styling, as well as how to deploy the website to the cloud and attach a custom domain. By the end of Part 1, you will have a working website that is ready to be connected to a database.</p>
<p>In Part 2, you will connect the Flask application from the first part to a cloud MySQL database, and learn how to deploy a production-ready database-driven web application. You will start by setting up the project and deployment, then move on to cloud MySQL database setup, and DB connection with SQLAlchemy. </p>
<p>You will learn how to display DB data on web pages, create dynamic database-driven pages, and build an HTML form for applications. Finally, you will learn how to save applications to the database, and wrap up the course by summarizing the topics covered and outlining future work.</p>
<p>By the end of the course, you will have the knowledge and skills needed to build and deploy a production-ready database-driven web application. This will not only enhance your skills as a developer but also open up new career opportunities. You will also have a deep understanding of Flask and MySQL, which will enable you to apply these skills to other projects.</p>
<p>So, if you're ready to take your web development skills to the next level, star watching <a target="_blank" href="https://youtu.be/yBDHkveJUf4">this 5-hour course</a> and continue your journey towards becoming a master web developer!</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/yBDHkveJUf4" 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>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build Secure APIs with Flask and Auth0 ]]>
                </title>
                <description>
                    <![CDATA[ APIs are at the heart of modern development. They support all kinds of systems, from mobile, web, and desktop applications, to IoT devices and self-driving cars. They are a bridge between your clients and your application logic and storage.  This cen... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-secure-apis-with-flask-and-auth0/</link>
                <guid isPermaLink="false">66d039d433e91331eb22953b</guid>
                
                    <category>
                        <![CDATA[ api ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Auth0 ]]>
                    </category>
                
                    <category>
                        <![CDATA[ authorization ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Flask Framework ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Security ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Juan Cruz Martinez ]]>
                </dc:creator>
                <pubDate>Wed, 08 Feb 2023 00:32:04 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/01/3.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>APIs are at the heart of modern development. They support all kinds of systems, from mobile, web, and desktop applications, to IoT devices and self-driving cars. They are a bridge between your clients and your application logic and storage. </p>
<p>This central access point to your application’s data raises the question: how can you provide access to the information to those who need it while denying access to unauthorized requests?</p>
<p>The industry has provided several protocols and best practices for securing APIs. Today we will focus on <a target="_blank" href="https://auth0.com/docs/authorization/protocols/protocol-oauth2?utm_source=freecodecamp?utm_source=freecodecamp&amp;utm_medium=sc&amp;utm_campaign=securing_flask">OAuth2</a>, one of the most popular options for authorizing clients into our APIs.</p>
<p>But how do we implement OAuth2? There are two ways to go about it:</p>
<ol>
<li>Do it yourself approach</li>
<li>Work with a safe 3rd party like <a target="_blank" href="https://auth0.com/?utm_source=freecodecamp&amp;utm_medium=sc&amp;utm_campaign=securing_flask">Auth0</a></li>
</ol>
<p>In this article, I will walk you through an implementation of OAuth2 for Python and <a target="_blank" href="https://flask.palletsprojects.com/">Flask</a> using Auth0 as our identity provider. But first, we are going to discuss the do-it-yourself approach.</p>
<h2 id="heading-why-not-build-your-own-authentication-and-authorization">Why Not Build Your Own Authentication and Authorization?</h2>
<p>For a few years now, I wanted to give back to the community that helped me so much by teaching me programming and helping me progress in my search for knowledge. I always thought that a great way to contribute was by having my own blog, a thing that I tried more than a few times and failed. </p>
<p>But where did I fail? Instead of focusing on writing, I tried to build my own blog engine because it’s in my nature. It’s what developers do. They love to build.</p>
<p>But why do I mention that here? Because many fall into the same trap when building APIs. Let me explain with an example.</p>
<p>Bob is a great developer, and he has this great idea for a ToDo app that can be the next big thing. Bob is very aware that for a successful implementation, users can only access their own data.</p>
<p>Here is bob’s application timeline:</p>
<ul>
<li>Sprint 0: Research ideas and start prototyping</li>
<li>Sprint 1: Build user table and login screen with API</li>
<li>Sprint 2: Add password reset screens and build all email templates</li>
<li>Sprint 3: Build, create and list ToDos screens</li>
<li>Sprint 4: MVP goes live</li>
<li>User feedback:<ul>
<li>Some users can’t log in due to a bug</li>
<li>Some users feel unsafe without 2-factor authentication</li>
<li>Some users don’t want to get yet another password. They prefer single sign-on with Google or Facebook.</li>
<li>…</li>
</ul>
</li>
</ul>
<p>Let’s talk about what happened. Bob spent the first few sprints not building his app but building the basic blocks, like logging in and out functionality, email notifications, and so on. This valuable time could have been spent differently, but what happens next is more concerning.</p>
<p>Bob’s backlog starts to fill in. Now, he needs to improvise a 2-factor authentication method, add single sign-on, and more non-product-related functions that could potentially delay his product.</p>
<p>And there’s still a big question to be answered: did Bob implement all the security mechanisms correctly? A critical error could expose all the user’s information to outsiders.</p>
<p>What Bob did is what I did with my blog many times. Sometimes, it's helpful to rely on 3rd parties if we want to get things done right.</p>
<p>Today, hackers and attacks have become so sophisticated that security is not a trivial factor anymore. It is a complicated system on its own, and it is often best to leave its implementation to experts – not only so it’s done right, but also so we can focus on what matters: building our applications and APIs.</p>
<h2 id="heading-how-to-set-up-a-free-auth0-identity-management-account">How to Set Up a Free Auth0 Identity Management Account</h2>
<p><a target="_blank" href="https://auth0.com/?utm_source=freecodecamp&amp;utm_medium=sc&amp;utm_campaign=securing_flask">Auth0</a> is a leading authentication and authorization provider, but let’s see how it can help Bob (or you) build a better app:</p>
<ol>
<li>It <a target="_blank" href="https://auth0.com/learn/finn-ai-saves-10-5-ongoing-engineering-time-auth0/?utm_source=freecodecamp&amp;utm_medium=sc&amp;utm_campaign=securing_flask">saves time</a></li>
<li>It’s <a target="_blank" href="https://auth0.com/security?utm_source=freecodecamp&amp;utm_medium=sc&amp;utm_campaign=securing_flask">secure</a></li>
<li>It has a <a target="_blank" href="https://auth0.com/pricing?utm_source=freecodecamp&amp;utm_medium=sc&amp;utm_campaign=securing_flask">free plan</a></li>
</ol>
<p>Time to get practical. First, make sure you have an Auth0 account. If not, you can create one <a target="_blank" href="https://auth0.com/signup/?utm_source=freecodecamp&amp;utm_medium=sc&amp;utm_campaign=securing_flask">here for free</a>.</p>
<h3 id="heading-create-a-new-auth0-api">Create a New Auth0 API</h3>
<p>There is still one more thing we have to do before we start coding. Head over to the <a target="_blank" href="https://manage.auth0.com/#/apis?utm_source=freecodecamp&amp;utm_medium=sc&amp;utm_campaign=securing_flask">APIs</a> section of your Auth0 dashboard and click on the “Create API” button. After that, fill in the form with your details. However, make sure you select <code>RS256</code> as the <code>Signing Algorithm</code>.</p>
<p>Your form should look like the following:</p>
<p><img src="https://lh5.googleusercontent.com/XccGez21ClEDsCECuKwiF_1AF5gj2OXXaJKEXVUOBFmxQ7Ci11a1g1O3cu_io185YbdnSJkAlu3dmP0pt6Ww-N6cPqQLTIeweSi2hNv4ototIkuSZhfiprjqcMrFhcMLaGkKfedkm8D0PR2IcjdLPGUChKS27wsiPMvqCsysQRJyGANVYc5Q5EbFdaFo" alt="Image" width="1298" height="1252" loading="lazy">
<em>Creating the API – image showing fields to fill out</em></p>
<p>The API details page opens after successfully creating an API. Keep that tab open, as it contains information we need to set up our application. If you close it, don’t worry, you can always access it again.</p>
<h2 id="heading-how-to-bootstrap-our-application">How to Bootstrap our Application</h2>
<p>Because we will focus on the security aspects only, we will take a few shortcuts when building our demo API. However, when developing <a target="_blank" href="https://livecodestream.dev/post/python-flask-api-starter-kit-and-project-layout/?utm_source=freecodecamp&amp;utm_medium=sc&amp;utm_campaign=securing_flask">actual APIs</a>, please follow <a target="_blank" href="https://auth0.com/blog/best-practices-for-flask-api-development/?utm_source=freecodecamp&amp;utm_medium=sc&amp;utm_campaign=securing_flask">best practices for Flask APIs</a>.</p>
<h3 id="heading-install-the-dependencies">Install the dependencies</h3>
<p>First, install the following dependencies for setting up Flask and authenticating users.</p>
<pre><code class="lang-shell">pipenv install flask python-dotenv python-jose flask-cors six
</code></pre>
<h3 id="heading-build-the-endpoints">Build the endpoints</h3>
<p>Our API will be straightforward. It will consist of only three endpoints, all of which, for now, will be publicly accessible. However, we will fix that soon. Here are our endpoints:</p>
<ul>
<li><code>/</code> (public endpoint)</li>
<li><code>/user</code> (requires a logged in user)</li>
<li><code>/admin</code> (only users of admin role)</li>
</ul>
<p>Let’s get to it:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> Flask

app = Flask(__name__)

<span class="hljs-meta">@app.route("/")</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">index_view</span>():</span>
    <span class="hljs-string">"""
    Default endpoint, it is public and can be accessed by anyone
    """</span>
    <span class="hljs-keyword">return</span> jsonify(msg=<span class="hljs-string">"Hello world!"</span>)

<span class="hljs-meta">@app.route("/user")</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">user_view</span>():</span>
    <span class="hljs-string">"""
    User endpoint, can only be accessed by an authorized user
    """</span>
    <span class="hljs-keyword">return</span> jsonify(msg=<span class="hljs-string">"Hello user!"</span>)

<span class="hljs-meta">@app.route("/admin")</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">admin_view</span>():</span>
    <span class="hljs-string">"""
    Admin endpoint, can only be accessed by an admin
    """</span>
    <span class="hljs-keyword">return</span> jsonify(msg=<span class="hljs-string">"Hello admin!"</span>)
</code></pre>
<p>Very simple right? Let’s run it:</p>
<pre><code class="lang-shell">~ pipenv run flask run
* Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
</code></pre>
<p>And if we access our endpoint:</p>
<pre><code class="lang-shell">~ curl -i http://localhost:5000
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 23
Server: Werkzeug/2.0.1 Python/3.9.1
Date: Tue, 24 Jan 2023 21:24:57 GMT

{"msg":"Hello world!"}

~ curl -i http://localhost:5000/user
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 22
Server: Werkzeug/2.0.1 Python/3.9.1
Date: Tue, 24 Jan 2023 21:25:42 GMT

{"msg":"Hello user!"}

~ curl -i http://localhost:5000/admin
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 23
Server: Werkzeug/2.0.1 Python/3.9.1
Date: Tue, 24 Jan 2023 21:26:18 GMT

{"msg":"Hello admin!"}
</code></pre>
<h2 id="heading-how-to-secure-the-endpoints">How to Secure the Endpoints</h2>
<p>As we are using OAuth, we will authenticate requests by validating an access token in <a target="_blank" href="https://auth0.com/learn/json-web-tokens/?utm_source=freecodecamp&amp;utm_medium=sc&amp;utm_campaign=securing_flask">JWT format</a>. We'll send it to the API on each request as part of the HTTP headers.</p>
<h3 id="heading-auth0-configuration-variables">Auth0 configuration variables</h3>
<p>As mentioned in the previous section, our API needs to be aware and will require information from our Auth0 dashboard. So head back to your <a target="_blank" href="https://manage.auth0.com/#/apis?utm_source=freecodecamp&amp;utm_medium=sc&amp;utm_campaign=securing_flask">API details page</a>, and grab two different values.</p>
<p><strong>First, the API Identifier:</strong></p>
<p>This is the value required when the API is created. You can also get it from your API details page:</p>
<p><img src="https://lh5.googleusercontent.com/UffKcasZXNZmXldeB8nhDEjzmOPVao3PR6EUVPbtWzXStuDzcCw2kr5ztEnr0VlWCkBLbhleAM-D11Cv5Cv8fcII8m24D6TfEe4XfxWe8HXN1aNrF-dHeN05zeVeoNfQISWh-VPf0__x8uVfJPL3GGHYIC87utfrr6734Z9Wdk-9eJUApslcdUKOyoSh" alt="Image" width="1600" height="699" loading="lazy">
<em>How to find the API identifier on the API details page</em></p>
<p><strong>Next, Auth0 domain:</strong></p>
<p>Unless you're using a custom domain, this value will be <a target="_blank"><code>[TENANT_NAME].auth0.com</code></a>, and you can grab it from the <code>Test</code> tab (make sure not to include <code>https://</code> and the last forward slash <code>/</code>).</p>
<p><img src="https://lh4.googleusercontent.com/cA63NdLr4AWOz2O3jTWBXTTqc7DrGOr1aPOIpNDRYl97-o84I_lX8KtotCm6hRWF06ai0RjiJzgTjS_zRlySKFAB-XO1w737N05i7-bC2-GZioOpcWuS5gaRoEnDL63gXnm5CyP6JOEQusRLQMF1sY_1vjfXtdMVIr5uCW1PMIpokH76lpMq2VFZSIyf" alt="Image" width="1600" height="1037" loading="lazy">
<em>Getting the Auth0 domain</em></p>
<p>Next, pass those values into variables so they can be used in the validation functions.</p>
<pre><code class="lang-python">AUTH0_DOMAIN = <span class="hljs-string">'YOUR-AUTH0-DOMAIN'</span>
API_IDENTIFIER = <span class="hljs-string">'API-IDENTIFIER'</span>
ALGORITHMS = [<span class="hljs-string">"RS256"</span>]
</code></pre>
<h3 id="heading-error-methods">Error methods</h3>
<p>During this implementation, we will need a way to throw errors when authentication fails. So we will use the following helpers for those needs:</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AuthError</span>(<span class="hljs-params">Exception</span>):</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, error, status_code</span>):</span>
        self.error = error
        self.status_code = status_code

<span class="hljs-meta">@app.errorhandler(AuthError)</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">handle_auth_error</span>(<span class="hljs-params">ex</span>):</span>
    response = jsonify(ex.error)
    response.status_code = ex.status_code
    <span class="hljs-keyword">return</span> response
</code></pre>
<h3 id="heading-how-to-capture-the-jwt-token">How to capture the JWT token</h3>
<p>The first step to validate a user is to retrieve the JWT token from the HTTP headers. This is very simple, but there are a few things to keep in mind. Here is an example of it:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_token_auth_header</span>():</span>
    <span class="hljs-string">"""
    Obtains the Access Token from the Authorization Header
    """</span>
    auth = request.headers.get(<span class="hljs-string">"Authorization"</span>, <span class="hljs-literal">None</span>)
    <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> auth:
        <span class="hljs-keyword">raise</span> AuthError({<span class="hljs-string">"code"</span>: <span class="hljs-string">"authorization_header_missing"</span>,
                        <span class="hljs-string">"description"</span>:
                            <span class="hljs-string">"Authorization header is expected"</span>}, <span class="hljs-number">401</span>)

    parts = auth.split()

    <span class="hljs-keyword">if</span> parts[<span class="hljs-number">0</span>].lower() != <span class="hljs-string">"bearer"</span>:
        <span class="hljs-keyword">raise</span> AuthError({<span class="hljs-string">"code"</span>: <span class="hljs-string">"invalid_header"</span>,
                        <span class="hljs-string">"description"</span>:
                            <span class="hljs-string">"Authorization header must start with"</span>
                            <span class="hljs-string">" Bearer"</span>}, <span class="hljs-number">401</span>)
    <span class="hljs-keyword">elif</span> len(parts) == <span class="hljs-number">1</span>:
        <span class="hljs-keyword">raise</span> AuthError({<span class="hljs-string">"code"</span>: <span class="hljs-string">"invalid_header"</span>,
                        <span class="hljs-string">"description"</span>: <span class="hljs-string">"Token not found"</span>}, <span class="hljs-number">401</span>)
    <span class="hljs-keyword">elif</span> len(parts) &gt; <span class="hljs-number">2</span>:
        <span class="hljs-keyword">raise</span> AuthError({<span class="hljs-string">"code"</span>: <span class="hljs-string">"invalid_header"</span>,
                        <span class="hljs-string">"description"</span>:
                            <span class="hljs-string">"Authorization header must be"</span>
                            <span class="hljs-string">" Bearer token"</span>}, <span class="hljs-number">401</span>)

    token = parts[<span class="hljs-number">1</span>]
    <span class="hljs-keyword">return</span> token
</code></pre>
<h3 id="heading-how-to-validate-the-token">How to validate the token</h3>
<p>Having a token passed to our API is a good sign, but it doesn’t mean that it is a valid client. We need to check the token signature.</p>
<p>Since the logic to require authentication can be used for more than one endpoint, it would be important to abstract it and make it easily accessible for developers to implement. The best way to do this is by using <a target="_blank" href="https://book.pythontips.com/en/latest/decorators.html">decorators</a>.</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">requires_auth</span>(<span class="hljs-params">f</span>):</span>
    <span class="hljs-string">"""
    Determines if the Access Token is valid
    """</span>
<span class="hljs-meta">    @wraps(f)</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">decorated</span>(<span class="hljs-params">*args, **kwargs</span>):</span>
        token = get_token_auth_header()
        jsonurl = urlopen(<span class="hljs-string">"https://"</span>+AUTH0_DOMAIN+<span class="hljs-string">"/.well-known/jwks.json"</span>)
        jwks = json.loads(jsonurl.read())
        unverified_header = jwt.get_unverified_header(token)
        rsa_key = {}
        <span class="hljs-keyword">for</span> key <span class="hljs-keyword">in</span> jwks[<span class="hljs-string">"keys"</span>]:
            <span class="hljs-keyword">if</span> key[<span class="hljs-string">"kid"</span>] == unverified_header[<span class="hljs-string">"kid"</span>]:
                rsa_key = {
                    <span class="hljs-string">"kty"</span>: key[<span class="hljs-string">"kty"</span>],
                    <span class="hljs-string">"kid"</span>: key[<span class="hljs-string">"kid"</span>],
                    <span class="hljs-string">"use"</span>: key[<span class="hljs-string">"use"</span>],
                    <span class="hljs-string">"n"</span>: key[<span class="hljs-string">"n"</span>],
                    <span class="hljs-string">"e"</span>: key[<span class="hljs-string">"e"</span>]
                }
        <span class="hljs-keyword">if</span> rsa_key:
            <span class="hljs-keyword">try</span>:
                payload = jwt.decode(
                    token,
                    rsa_key,
                    algorithms=ALGORITHMS,
                    audience=API_IDENTIFIER,
                    issuer=<span class="hljs-string">"https://"</span>+AUTH0_DOMAIN+<span class="hljs-string">"/"</span>
                )
            <span class="hljs-keyword">except</span> jwt.ExpiredSignatureError:
                <span class="hljs-keyword">raise</span> AuthError({<span class="hljs-string">"code"</span>: <span class="hljs-string">"token_expired"</span>,
                                <span class="hljs-string">"description"</span>: <span class="hljs-string">"token is expired"</span>}, <span class="hljs-number">401</span>)
            <span class="hljs-keyword">except</span> jwt.JWTClaimsError:
                <span class="hljs-keyword">raise</span> AuthError({<span class="hljs-string">"code"</span>: <span class="hljs-string">"invalid_claims"</span>,
                                <span class="hljs-string">"description"</span>:
                                    <span class="hljs-string">"incorrect claims,"</span>
                                    <span class="hljs-string">"please check the audience and issuer"</span>}, <span class="hljs-number">401</span>)
            <span class="hljs-keyword">except</span> Exception:
                <span class="hljs-keyword">raise</span> AuthError({<span class="hljs-string">"code"</span>: <span class="hljs-string">"invalid_header"</span>,
                                <span class="hljs-string">"description"</span>:
                                    <span class="hljs-string">"Unable to parse authentication"</span>
                                    <span class="hljs-string">" token."</span>}, <span class="hljs-number">401</span>)

            _request_ctx_stack.top.current_user = payload
            <span class="hljs-keyword">return</span> f(*args, **kwargs)
        <span class="hljs-keyword">raise</span> AuthError({<span class="hljs-string">"code"</span>: <span class="hljs-string">"invalid_header"</span>,
                        <span class="hljs-string">"description"</span>: <span class="hljs-string">"Unable to find appropriate key"</span>}, <span class="hljs-number">401</span>)
    <span class="hljs-keyword">return</span> decorated
</code></pre>
<p>The newly created <code>requires_auth</code> decorator, when applied to an endpoint, will automatically reject the request if no valid user can be authenticated.</p>
<h3 id="heading-how-to-require-an-authenticated-request-for-an-endpoint">How to require an authenticated request for an endpoint</h3>
<p>We are ready to secure our endpoints, let’s update the <code>user</code> and <code>admin</code> endpoints to utilize our decorator.</p>
<pre><code class="lang-python"><span class="hljs-meta">@app.route("/user")</span>
<span class="hljs-meta">@requires_auth</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">user_view</span>():</span>
    <span class="hljs-string">"""
    User endpoint, can only be accessed by an authorized user
    """</span>
    <span class="hljs-keyword">return</span> jsonify(msg=<span class="hljs-string">"Hello user!"</span>)

<span class="hljs-meta">@app.route("/admin")</span>
<span class="hljs-meta">@requires_auth</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">admin_view</span>():</span>
    <span class="hljs-string">"""
    Admin endpoint, can only be accessed by an admin
    """</span>
    <span class="hljs-keyword">return</span> jsonify(msg=<span class="hljs-string">"Hello admin!"</span>)
</code></pre>
<p>Our only change was adding <code>@required_auth</code> at the top of the declaration of each endpoint function, and with that we can test once again:</p>
<pre><code class="lang-shell">~ curl -i http://localhost:5000/user
HTTP/1.0 401 UNAUTHORIZED
Content-Type: application/json
Content-Length: 89
Server: Werkzeug/2.0.1 Python/3.9.1
Date: Tue, 24 Jan 2023 21:42:26 GMT

{"code":"authorization_header_missing","description":"Authorization header is expected"}

~ curl -i http://localhost:5000/admin
HTTP/1.0 401 UNAUTHORIZED
Content-Type: application/json
Content-Length: 89
Server: Werkzeug/2.0.1 Python/3.9.1
Date: Tue, 24 Jan 2023 21:42:42 GMT

{"code":"authorization_header_missing","description":"Authorization header is expected"}
</code></pre>
<p>As expected, we can’t access our endpoints as the authorization header is missing. But before we add one, let’s see if our public endpoint still works:</p>
<pre><code class="lang-shell">~ curl -i http://localhost:5000
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 23
Server: Werkzeug/2.0.1 Python/3.9.1
Date: Tue, 24 Jan 2023 21:43:55 GMT

{"msg":"Hello world!"}
</code></pre>
<p>Awesome, it works as expected.</p>
<h3 id="heading-how-to-test-it-out">How to test it out</h3>
<p>For testing our newly secured endpoints, we need to get a valid access token that we can pass to the request. We can do that directly on the <code>Test</code> tab on the API details page, and it’s as simple as copying a value from the screen:  </p>
<p><img src="https://lh5.googleusercontent.com/XCAWL5taQUs3_5qcAdukl9FP_aTVLya-jyS_4IivFW6JCAfX5d2hbPPCIV4PB8QgcuceQrzC__YYpWMQB1y8HT9AnKO01XH5rCiofvQJAmiAPnGF42FcJFxaVHTLLQcL9UpzFjYgan0Qasna69DlZ8AIkoATbqAtqtqibWUszhvakHZiytPNduTU7_Hb" alt="Image" width="1600" height="1062" loading="lazy">
<em>Copying the token for testing</em></p>
<p>Once we have the token we can change our curl request accordingly:</p>
<pre><code class="lang-shell">~ curl -i -H "Authorization: bearer [ACCESS_TOKEN]"  http://localhost:5000/user
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 22
Server: Werkzeug/2.0.1 Python/3.9.1
Date: Tue, 24 Jan 2023 22:17:06 GMT

{"msg":"Hello user!"}
</code></pre>
<p>Please remember to replace <code>[ACCESS_TOKEN]</code> with the value you copied from the dashboard.</p>
<p>It works! But we still have some work to do. Even though our <code>/admin</code> endpoint is secured, it can be accessed by any user:</p>
<pre><code class="lang-shell">~ curl -i -H "Authorization: bearer [ACCESS_TOKEN]"  http://localhost:5000/admin
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 23
Server: Werkzeug/2.0.1 Python/3.9.1
Date: Tue, 24 Jan 2023 22:21:09 GMT

{"msg":"Hello admin!"}
</code></pre>
<h3 id="heading-role-based-access-control">Role-based access control</h3>
<p>For role-based access control there’s a few things we need to do:</p>
<ol>
<li>Create permissions for the API</li>
<li>Enable adding permissions to the JWT for the API</li>
<li>Update the code</li>
<li>Test with users</li>
</ol>
<p>The first 2 points are very well explained in the <a target="_blank" href="https://auth0.com/docs/authorization/rbac/auth-core-features?utm_source=freecodecamp&amp;utm_medium=sc&amp;utm_campaign=securing_flask">Auth0 docs</a>, so just make sure you add the corresponding permissions on your API. </p>
<p>Next, we need to update the code. We need a function to check if a given permission exists in the access token and return <code>True</code> if it does and <code>False</code> if it does not:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">requires_scope</span>(<span class="hljs-params">required_scope</span>):</span>
    <span class="hljs-string">"""
    Determines if the required scope is present in the Access Token
    Args:
        required_scope (str): The scope required to access the resource
    """</span>
    token = get_token_auth_header()
    unverified_claims = jwt.get_unverified_claims(token)
    <span class="hljs-keyword">if</span> unverified_claims.get(<span class="hljs-string">"scope"</span>):
            token_scopes = unverified_claims[<span class="hljs-string">"scope"</span>].split()
            <span class="hljs-keyword">for</span> token_scope <span class="hljs-keyword">in</span> token_scopes:
                <span class="hljs-keyword">if</span> token_scope == required_scope:
                    <span class="hljs-keyword">return</span> <span class="hljs-literal">True</span>
    <span class="hljs-keyword">return</span> <span class="hljs-literal">False</span>
</code></pre>
<p>And lastly, it can be used as follows:</p>
<pre><code class="lang-python"><span class="hljs-meta">@app.route("/admin")</span>
<span class="hljs-meta">@requires_auth</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">admin_view</span>():</span>
    <span class="hljs-string">"""
    Admin endpoint, can only be accessed by an admin
    """</span>
    <span class="hljs-keyword">if</span> requires_scope(<span class="hljs-string">"read:admin"</span>):
        <span class="hljs-keyword">return</span> jsonify(msg=<span class="hljs-string">"Hello admin!"</span>)

    <span class="hljs-keyword">raise</span> AuthError({
        <span class="hljs-string">"code"</span>: <span class="hljs-string">"Unauthorized"</span>,
        <span class="hljs-string">"description"</span>: <span class="hljs-string">"You don't have access to this resource"</span>
    }, <span class="hljs-number">403</span>)
</code></pre>
<p>Now, only users with the permission <code>read:admin</code> can access our admin endpoint.</p>
<p>In order to test your final implementation, you can follow the steps detailed on <a target="_blank" href="https://auth0.com/docs/quickstart/backend/python/02-using#obtaining-an-access-token?utm_source=freecodecamp&amp;utm_medium=sc&amp;utm_campaign=securing_flask">obtaining an access token</a> for a given user. </p>
<p>You can also use the Auth0 Dashboard to test permissions, but that is outside the scope of this article. If you would like to learn more about it, read <a target="_blank" href="https://auth0.com/blog/permission-based-security-aspnet-webapi/#Testing-Permissions">here</a>.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Today we learned how to secure a Flask API. We explored the do-it-yourself path, and we built a secure API with three levels of access – public access, private access and privately-scoped access.</p>
<p>There’s so much more that Auth0 can do for your APIs and also for your client applications. Today we just scratched the surface, and it’s up to you and your team when working with real-life scenarios to explore all the potential of their services.</p>
<p>The full code is available on <a target="_blank" href="https://gist.github.com/bajcmartinez/5062aa41ccbe2df1bbf4f1a9b95bd085">GitHub</a>.</p>
<p>Thanks for reading! If you like my teaching style, you can <a target="_blank" href="https://livecodestream.dev/newsletter/">Subscribe to my weekly newsletter</a> for developers and builders and get a weekly email with relevant content<em>.</em></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Set Up Email Verification in a Flask App ]]>
                </title>
                <description>
                    <![CDATA[ Email verification is a crucial aspect of creating a new user account or signing up for a service. It helps confirm that the email address provided is valid and belongs to the intended user. In this article, we will explore the process of handling em... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/setup-email-verification-in-flask-app/</link>
                <guid isPermaLink="false">66ba0ec4d14c87384322b699</guid>
                
                    <category>
                        <![CDATA[ Flask Framework ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ashutosh Krishna ]]>
                </dc:creator>
                <pubDate>Mon, 09 Jan 2023 17:56:18 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/01/pexels-maksim-goncharenok-5605061.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Email verification is a crucial aspect of creating a new user account or signing up for a service. It helps confirm that the email address provided is valid and belongs to the intended user.</p>
<p>In this article, we will explore the process of handling email verification in Flask. The topic will include setting up a route to handle the email verification process, and storing the verification status in a database. </p>
<p>By the end of this article, you will have a thorough understanding of how to implement email verification in your own Flask application.</p>
<p>Before getting started, make sure you have a good understanding of basic user authentication in Flask. You can go through <a target="_blank" href="https://ashutoshkrris.hashnode.dev/how-to-set-up-basic-user-authentication-in-a-flask-app">this tutorial</a> to learn more.</p>
<h2 id="heading-project-demo"><strong>Project Demo</strong></h2>
<p>Here’s what you're going to build in this tutorial:</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/7o-wY65gHD8" 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>The link to the GitHub repository is available at the end of the tutorial. Feel free to check it out whenever you're stuck.</p>
<h2 id="heading-flask-basic-user-authentication">Flask Basic User Authentication</h2>
<p>To begin, you will use a Flask boilerplate that includes basic user authentication. You can get the code from <a target="_blank" href="https://github.com/ashutoshkrris/Flask-User-Authentication">this repository</a>. After creating and activating a virtual environment, run the following command to install all the dependencies:</p>
<pre><code class="lang-bash">$ pip install -r requirements.txt
</code></pre>
<p>Create a file named <code>.env</code> in the root directory and add the following content there:</p>
<pre><code><span class="hljs-keyword">export</span> SECRET_KEY=fdkjshfhjsdfdskfdsfdcbsjdkfdsdf
<span class="hljs-keyword">export</span> DEBUG=True
<span class="hljs-keyword">export</span> APP_SETTINGS=config.DevelopmentConfig
<span class="hljs-keyword">export</span> DATABASE_URL=sqlite:<span class="hljs-comment">///db.sqlite</span>
<span class="hljs-keyword">export</span> FLASK_APP=src
<span class="hljs-keyword">export</span> FLASK_DEBUG=<span class="hljs-number">1</span>
</code></pre><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>Run the following commands to set up the database:</p>
<pre><code class="lang-bash">flask db init
flask db upgrade
</code></pre>
<p>Run the following command to run the Flask server:</p>
<pre><code class="lang-bash">python manage.py run
</code></pre>
<p>Once the app is running, go to <a target="_blank" href="http://localhost:5000/register">http://localhost:5000/register</a> to register a new user. You will notice that after completing the registration, the app will automatically log you in and redirect you to the main page.</p>
<p>Before proceeding, I'd recommend exploring the app and then reviewing the code, particularly the <strong>accounts</strong> blueprint. This will give you a better understanding of how the user authentication is implemented.</p>
<h2 id="heading-how-to-modify-the-current-implementation">How to Modify the Current Implementation</h2>
<p>In this section, you will modify the existing implementation of user authentication in our Flask app.</p>
<h3 id="heading-models">Models</h3>
<p>First of all, you'll need to add two new fields – <code>is_confirmed</code> and <code>confirmed_on</code> in the <code>User</code> model of your app.</p>
<p>Open the <code>src/accounts/models.py</code> file and update the <code>User</code> class with the following:</p>
<pre><code class="lang-python"><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>

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

    id = db.Column(db.Integer, primary_key=<span class="hljs-literal">True</span>)
    email = 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_on = db.Column(db.DateTime, nullable=<span class="hljs-literal">False</span>)
    is_admin = db.Column(db.Boolean, nullable=<span class="hljs-literal">False</span>, default=<span class="hljs-literal">False</span>)
    is_confirmed = db.Column(db.Boolean, nullable=<span class="hljs-literal">False</span>, default=<span class="hljs-literal">False</span>)
    confirmed_on = db.Column(db.DateTime, nullable=<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, email, password, is_admin=False, is_confirmed=False, confirmed_on=None
    </span>):</span>
        self.email = email
        self.password = bcrypt.generate_password_hash(password)
        self.created_on = datetime.now()
        self.is_admin = is_admin
        self.is_confirmed = is_confirmed
        self.confirmed_on = confirmed_on

    <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;email <span class="hljs-subst">{self.email}</span>&gt;"</span>
</code></pre>
<p>The <code>is_confirmed</code> is a boolean field to indicate whether the user's email address has been confirmed, set as not nullable and defaulting to <code>False</code>. The <code>confirmed_on</code> is a <code>datetime</code> field for the time when the user's email was confirmed, set as nullable.</p>
<p>To migrate and apply these changes in the database, run the following commands:</p>
<pre><code class="lang-bash">flask db migrate
flask db upgrade
</code></pre>
<h3 id="heading-how-to-create-the-admin">How to create the admin</h3>
<p>Next, in the <code>manage.py</code> file, update the <code>create_admin</code> command to take the new database fields into account:</p>
<pre><code class="lang-python"><span class="hljs-meta">@cli.command("create_admin")</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">create_admin</span>():</span>
    <span class="hljs-string">"""Creates the admin user."""</span>
    email = input(<span class="hljs-string">"Enter email address: "</span>)
    password = getpass.getpass(<span class="hljs-string">"Enter password: "</span>)
    confirm_password = getpass.getpass(<span class="hljs-string">"Enter password again: "</span>)
    <span class="hljs-keyword">if</span> password != confirm_password:
        print(<span class="hljs-string">"Passwords don't match"</span>)
    <span class="hljs-keyword">else</span>:
        <span class="hljs-keyword">try</span>:
            user = User(
                email=email,
                password=password,
                is_admin=<span class="hljs-literal">True</span>,
                is_confirmed=<span class="hljs-literal">True</span>,
                confirmed_on=datetime.now(),
            )
            db.session.add(user)
            db.session.commit()
            print(<span class="hljs-string">f"Admin with email <span class="hljs-subst">{email}</span> created successfully!"</span>)
        <span class="hljs-keyword">except</span> Exception:
            print(<span class="hljs-string">"Couldn't create admin user."</span>)
</code></pre>
<p>Notice that the <code>is_confirmed</code> field is set to <code>True</code> in this case because you don't want the admin to verify their account.</p>
<h3 id="heading-how-to-add-a-new-decorator-to-check-if-the-user-is-logged-out">How to add a new decorator to check if the user is logged out</h3>
<p>If you notice the <code>register()</code> and <code>login()</code> function in <code>src/accounts/views.py</code>, you'll find the below code in both of them:</p>
<pre><code class="lang-python"><span class="hljs-keyword">if</span> current_user.is_authenticated:
    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(<span class="hljs-string">"core.home"</span>))
</code></pre>
<p>The code checks whether a user is already logged in. If the user is authenticated, a message is displayed using the <code>flash</code> function and the user is redirected to the home page using the <code>redirect</code> function from Flask. </p>
<p>If the user is not authenticated, they will be allowed to continue with the process they were trying to complete. This essentially means you require the user to be logged out to continue the flow.</p>
<p>Instead of repeating the code at two places, you can create a decorator to check if the user is logged out.</p>
<p>Create a new <code>utils</code> folder in the <code>src</code> folder, and a <code>decorators.py</code> file in the <code>utils</code> folder with the following content:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> functools <span class="hljs-keyword">import</span> wraps

<span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> flash, redirect, url_for
<span class="hljs-keyword">from</span> flask_login <span class="hljs-keyword">import</span> current_user


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">logout_required</span>(<span class="hljs-params">func</span>):</span>
<span class="hljs-meta">    @wraps(func)</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">decorated_function</span>(<span class="hljs-params">*args, **kwargs</span>):</span>
        <span class="hljs-keyword">if</span> current_user.is_authenticated:
            flash(<span class="hljs-string">"You are already authenticated."</span>, <span class="hljs-string">"info"</span>)
            <span class="hljs-keyword">return</span> redirect(url_for(<span class="hljs-string">"core.home"</span>))
        <span class="hljs-keyword">return</span> func(*args, **kwargs)

    <span class="hljs-keyword">return</span> decorated_function
</code></pre>
<p>The above code defines a decorator called <code>logout_required</code> which is used to wrap routes in a Flask app. </p>
<p>If the user is authenticated, a message is displayed using the <code>flash</code> function and the user is redirected to the home page using the <code>redirect</code> function from Flask. If the user is not authenticated, they will be allowed to continue and the decorated route function will be executed.</p>
<p>Now, you can use this decorator in the <code>register()</code> and <code>login()</code> function as below:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> src.utils.decorators <span class="hljs-keyword">import</span> logout_required


<span class="hljs-meta">@accounts_bp.route("/register", methods=["GET", "POST"])</span>
<span class="hljs-meta">@logout_required</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">register</span>():</span>
    ...


<span class="hljs-meta">@accounts_bp.route("/login", methods=["GET", "POST"])</span>
<span class="hljs-meta">@logout_required</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">login</span>():</span>
    ...
</code></pre>
<h2 id="heading-how-to-add-email-verification-to-your-flask-app">How to Add Email Verification to Your Flask App</h2>
<p>In this section, you will learn how to add email verification to your Flask app.</p>
<h3 id="heading-confirmation-token">Confirmation token</h3>
<p>The email confirmation should contain a unique URL that the user can click to confirm their account. The URL should be in the following format: <code>http://localhost:5000/confirm/&lt;id&gt;</code>. </p>
<p>The <code>&lt;id&gt;</code> portion of the URL is a unique identifier that is generated using the user's email address and a timestamp. We can use the <a target="_blank" href="http://pythonhosted.org/itsdangerous/">itsdangerous</a> package to encode this information in the <code>&lt;id&gt;</code>. When the user clicks the link, the app can decode the <code>&lt;id&gt;</code> to retrieve the user's email address and verify their account.</p>
<p>To provide an additional layer of security to the token, the <code>itsdangerours</code> package requires a password salt. You can set an environment variable for the same in the <code>.env</code> file:</p>
<pre><code>other env vars...
export SECURITY_PASSWORD_SALT=fkslkfsdlkfnsdfnsfd
</code></pre><p>Run the following command to export the environment variable from the <code>.env</code> file:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">source</span> .env
</code></pre>
<p>Add the <code>SECURITY_PASSWORD_SALT</code> to your app’s config (<code>Config</code>) in the <code>config.py</code> file:</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Config</span>:</span>
    ...other configs
    SECURITY_PASSWORD_SALT = config(<span class="hljs-string">"SECURITY_PASSWORD_SALT"</span>, default=<span class="hljs-string">"very-important"</span>)
</code></pre>
<p>Create a <code>src/accounts/token.py</code> file and add the following code:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> itsdangerous <span class="hljs-keyword">import</span> URLSafeTimedSerializer

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


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">generate_token</span>(<span class="hljs-params">email</span>):</span>
    serializer = URLSafeTimedSerializer(app.config[<span class="hljs-string">"SECRET_KEY"</span>])
    <span class="hljs-keyword">return</span> serializer.dumps(email, salt=app.config[<span class="hljs-string">"SECURITY_PASSWORD_SALT"</span>])


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">confirm_token</span>(<span class="hljs-params">token, expiration=<span class="hljs-number">3600</span></span>):</span>
    serializer = URLSafeTimedSerializer(app.config[<span class="hljs-string">"SECRET_KEY"</span>])
    <span class="hljs-keyword">try</span>:
        email = serializer.loads(
            token, salt=app.config[<span class="hljs-string">"SECURITY_PASSWORD_SALT"</span>], max_age=expiration
        )
        <span class="hljs-keyword">return</span> email
    <span class="hljs-keyword">except</span> Exception:
        <span class="hljs-keyword">return</span> <span class="hljs-literal">False</span>
</code></pre>
<p>This code defines two functions for generating and confirming tokens for email verification in a Flask app:</p>
<p>The <code>generate_token</code> function takes an email address as an argument and returns a token that is generated using the <code>URLSafeTimedSerializer</code> class from the <code>itsdangerous</code> package. </p>
<p>The <code>URLSafeTimedSerializer</code> class is initialized with the app's secret key, which is stored in the <code>SECRET_KEY</code> configuration variable. The <code>dumps</code> method of the <code>URLSafeTimedSerializer</code> instance is called with the email address and a password salt as arguments. As mentioned earlier, the password salt is stored in the <code>SECURITY_PASSWORD_SALT</code> configuration variable.</p>
<p>The <code>confirm_token</code> function takes a token and an optional expiration time as arguments and returns the email address that was used to generate the token. </p>
<p>The <code>URLSafeTimedSerializer</code> instance is initialized with the app's secret key, and the <code>loads</code> method is called with the token, password salt, and expiration time as arguments. </p>
<p>If the token is valid and has not expired, the email address is returned. If the token is invalid or has expired, an exception is raised and caught by the <code>except</code> block, causing the function to return <code>False</code>.</p>
<h3 id="heading-how-to-update-the-register-function">How to update the <code>register()</code> function</h3>
<p>When the user registers, you need to generate a token using the email address of the user.</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> src.accounts.token <span class="hljs-keyword">import</span> confirm_token, generate_token


<span class="hljs-meta">@accounts_bp.route("/register", methods=["GET", "POST"])</span>
<span class="hljs-meta">@logout_required</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">register</span>():</span>
    form = RegisterForm(request.form)
    <span class="hljs-keyword">if</span> form.validate_on_submit():
        user = User(email=form.email.data, password=form.password.data)
        db.session.add(user)
        db.session.commit()

        token = generate_token(user.email)

        ...
</code></pre>
<p>The <code>token</code> variable will be used while sending an email to the user with the token included in the email's URL.</p>
<h3 id="heading-how-to-handle-email-confirmation">How to handle email confirmation</h3>
<p>To confirm the email, create a new view function in the <code>src/accounts/views.py</code> file:</p>
<pre><code class="lang-python"><span class="hljs-meta">@accounts_bp.route("/confirm/&lt;token&gt;")</span>
<span class="hljs-meta">@login_required</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">confirm_email</span>(<span class="hljs-params">token</span>):</span>
    <span class="hljs-keyword">if</span> current_user.is_confirmed:
        flash(<span class="hljs-string">"Account already confirmed."</span>, <span class="hljs-string">"success"</span>)
        <span class="hljs-keyword">return</span> redirect(url_for(<span class="hljs-string">"core.home"</span>))
    email = confirm_token(token)
    user = User.query.filter_by(email=current_user.email).first_or_404()
    <span class="hljs-keyword">if</span> user.email == email:
        user.is_confirmed = <span class="hljs-literal">True</span>
        user.confirmed_on = datetime.now()
        db.session.add(user)
        db.session.commit()
        flash(<span class="hljs-string">"You have confirmed your account. Thanks!"</span>, <span class="hljs-string">"success"</span>)
    <span class="hljs-keyword">else</span>:
        flash(<span class="hljs-string">"The confirmation link is invalid or has expired."</span>, <span class="hljs-string">"danger"</span>)
    <span class="hljs-keyword">return</span> redirect(url_for(<span class="hljs-string">"core.home"</span>))
</code></pre>
<p>The above code defines a route for the <code>confirm_email</code> view function in a Flask app. The route is decorated with the <code>@login_required</code> decorator, which requires the user to be logged in to access the view. The route takes a <code>token</code> argument, which is included in the URL of the route.</p>
<p>The view function first checks if the user's account is already confirmed. If the account is already confirmed, a message is displayed using the <code>flash</code> function from the Flask-Babel library and the user is redirected to the home page using the <code>redirect</code> function from Flask.</p>
<p>If the account is not confirmed, the <code>confirm_token</code> function is called with the <code>token</code> as an argument to confirm the token and retrieve the email address that was used to generate the token. If the token is invalid or has expired, the <code>confirm_token</code> function returns <code>False</code>, and a message is displayed indicating that the confirmation link is invalid or has expired.</p>
<p>If the token is valid, the user's account is confirmed by setting the <code>is_confirmed</code> field to <code>True</code> and the <code>confirmed_on</code> field to the current time. The changes are then committed to the database. A message is displayed indicating that the account has been confirmed, and the user is redirected to the home page.</p>
<h3 id="heading-how-to-send-email-confirmation">How to send email confirmation</h3>
<p>Let's first create a basic email template that will be used while sending the email. Create a <code>templates/accounts/confirm_email.html</code> file and add the following code:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
  Welcome! Thanks for signing up. Please follow this link to activate your
  account:
<span class="hljs-tag">&lt;/<span class="hljs-name">p</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">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"{{ confirm_url }}"</span>&gt;</span>{{ confirm_url }}<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">br</span> /&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Cheers!<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
</code></pre>
<p>The <code>confirm_url</code> placeholder is used to insert a URL into the email message. When the template is rendered, the <code>confirm_url</code> placeholder is replaced with the actual URL that the user should visit to confirm their account.</p>
<h4 id="heading-how-to-set-up-flask-mail">How to set up Flask-Mail</h4>
<p>Next, you'll need a library called <code>Flask-Mail</code> to send out emails using Flask.</p>
<p>Install the library using the pip command:</p>
<pre><code class="lang-bash">pip install Flask-Mail
</code></pre>
<p>Initialize the <code>Flask-Mail</code> library inside the <code>src/__init__.py</code> file as:</p>
<pre><code class="lang-python">...other imports...
<span class="hljs-keyword">from</span> flask_mail <span class="hljs-keyword">import</span> Mail

...other initializations...
mail = Mail(app)
...
</code></pre>
<p>You can set environment variables for your email and password that will be used to send emails in the <code>.env</code> file:</p>
<pre><code><span class="hljs-keyword">export</span> EMAIL_USER=your-email
<span class="hljs-keyword">export</span> EMAIL_PASSWORD=your-password
</code></pre><p>Run the following command to export 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>Update the <code>Config</code> class in the <code>config.py</code> file:</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Config</span>(<span class="hljs-params">object</span>):</span>
    ...other configs

    <span class="hljs-comment"># Mail Settings</span>
    MAIL_DEFAULT_SENDER = <span class="hljs-string">"noreply@flask.com"</span>
    MAIL_SERVER = <span class="hljs-string">"smtp.gmail.com"</span>
    MAIL_PORT = <span class="hljs-number">465</span>
    MAIL_USE_TLS = <span class="hljs-literal">False</span>
    MAIL_USE_SSL = <span class="hljs-literal">True</span>
    MAIL_DEBUG = <span class="hljs-literal">False</span>
    MAIL_USERNAME = config(<span class="hljs-string">"EMAIL_USER"</span>)
    MAIL_PASSWORD = config(<span class="hljs-string">"EMAIL_PASSWORD"</span>)
</code></pre>
<blockquote>
<p>Note: If your Gmail account has <a target="_blank" href="https://support.google.com/accounts/topic/28786?hl=en&amp;ref_topic=3382253">2-step authentication</a>, Google will block the attempt. Use an <a target="_blank" href="https://support.google.com/accounts/answer/185833?hl=en">app password</a> to sign in.</p>
</blockquote>
<h4 id="heading-how-to-create-a-function-to-send-email">How to create a function to send email</h4>
<p>Next, create a <code>email.py</code> file in the <code>src/utils</code> folder and add the following code:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> flask_mail <span class="hljs-keyword">import</span> Message

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


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">send_email</span>(<span class="hljs-params">to, subject, template</span>):</span>
    msg = Message(
        subject,
        recipients=[to],
        html=template,
        sender=app.config[<span class="hljs-string">"MAIL_DEFAULT_SENDER"</span>],
    )
    mail.send(msg)
</code></pre>
<p>The function takes three arguments: the recipient's email address (<code>to</code>), the subject of the email (<code>subject</code>), and the body of the email (<code>template</code>). </p>
<p>The <code>Message</code> class from the Flask-Mail library is used to create a new email message with the specified subject and recipient. The <code>html</code> argument is used to set the body of the email to the provided <code>template</code>, which is expected to be an HTML string. The <code>sender</code> argument is used to specify the default sender for the email, which is stored in the <code>MAIL_DEFAULT_SENDER</code> configuration variable.</p>
<p>The <code>send</code> method of the <code>mail</code> object is then called with the message object as an argument to send the email. </p>
<h4 id="heading-how-to-send-the-email-finally">How to send the email (finally)</h4>
<p>Let's finally send the confirmation email from the <code>register()</code> function:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> src.utils.email <span class="hljs-keyword">import</span> send_email


<span class="hljs-meta">@accounts_bp.route("/register", methods=["GET", "POST"])</span>
<span class="hljs-meta">@logout_required</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">register</span>():</span>
    form = RegisterForm(request.form)
    <span class="hljs-keyword">if</span> form.validate_on_submit():
        user = User(email=form.email.data, password=form.password.data)
        db.session.add(user)
        db.session.commit()
        token = generate_token(user.email)
        confirm_url = url_for(<span class="hljs-string">"accounts.confirm_email"</span>, token=token, _external=<span class="hljs-literal">True</span>)
        html = render_template(<span class="hljs-string">"accounts/confirm_email.html"</span>, confirm_url=confirm_url)
        subject = <span class="hljs-string">"Please confirm your email"</span>
        send_email(user.email, subject, html)

        login_user(user)

        flash(<span class="hljs-string">"A confirmation email has been sent via email."</span>, <span class="hljs-string">"success"</span>)
        <span class="hljs-keyword">return</span> redirect(url_for(<span class="hljs-string">"accounts.inactive"</span>))

    <span class="hljs-keyword">return</span> render_template(<span class="hljs-string">"accounts/register.html"</span>, form=form)
</code></pre>
<p>The <code>url_for</code> function is then called to generate a URL for the <code>confirm_email</code> route with the <code>token</code> as an argument. The <code>_external</code> argument is set to <code>True</code> to generate an absolute URL with the full domain name. The <code>render_template</code> function is called to render an HTML template for the email message, using the <code>confirm_url</code> as a placeholder in the template.</p>
<p>The <code>send_email</code> function is then called to send the email with the rendered template as the body, using the user's email address as the recipient and a subject of "Please confirm your email".</p>
<p>Finally, the user is logged in using the <code>login_user</code> function from the Flask-Login library and a message is displayed indicating that a confirmation email has been sent. The user is then redirected to the <code>inactive</code> view. You'll create it later.</p>
<p>A sample email looks like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/Screenshot-2023-01-05-234354.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-how-to-handle-inactive-accounts">How to Handle Inactive Accounts</h2>
<p>Whenever you create a new account, you're redirected to a view called <code>inactive</code> where you're asked to confirm your account.</p>
<p>Let's create a view function in the <code>src/accounts/views.py</code> file:</p>
<pre><code class="lang-python"><span class="hljs-meta">@accounts_bp.route("/inactive")</span>
<span class="hljs-meta">@login_required</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">inactive</span>():</span>
    <span class="hljs-keyword">if</span> current_user.is_confirmed:
        <span class="hljs-keyword">return</span> redirect(url_for(<span class="hljs-string">"core.home"</span>))
    <span class="hljs-keyword">return</span> render_template(<span class="hljs-string">"accounts/inactive.html"</span>)
</code></pre>
<p>The view function checks if the user's account is confirmed. If the account is confirmed, the user is redirected to the home page using the <code>redirect</code> function from Flask. If the account is not confirmed, the <code>inactive.html</code> template is rendered using the <code>render_template</code> function from Flask.</p>
<p>Let's create the <code>inactive.html</code> file in <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">"text-center"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Welcome!<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">br</span> /&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
    You have not confirmed your account. Please check your inbox (and your spam
    folder) - you should have received an email with a confirmation link.
  <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
    Didn't get the email?
    <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"{{ url_for('accounts.resend_confirmation') }}"</span>&gt;</span>Resend<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">div</span>&gt;</span>

{% endblock %}
</code></pre>
<p>The template includes a link to the <code>resend_confirmation</code> route.</p>
<h3 id="heading-how-to-resend-the-email">How to resend the email</h3>
<p>Consider a case where the user was not able to confirm the account before the expiration time of the token. As a user, you'll want to have an option to resend the email, right?</p>
<p>Create a new view function in the <code>src/accounts/views.py</code>:</p>
<pre><code class="lang-python"><span class="hljs-meta">@accounts_bp.route("/resend")</span>
<span class="hljs-meta">@login_required</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">resend_confirmation</span>():</span>
    <span class="hljs-keyword">if</span> current_user.is_confirmed:
        flash(<span class="hljs-string">"Your account has already been confirmed."</span>, <span class="hljs-string">"success"</span>)
        <span class="hljs-keyword">return</span> redirect(url_for(<span class="hljs-string">"core.home"</span>))
    token = generate_token(current_user.email)
    confirm_url = url_for(<span class="hljs-string">"accounts.confirm_email"</span>, token=token, _external=<span class="hljs-literal">True</span>)
    html = render_template(<span class="hljs-string">"accounts/confirm_email.html"</span>, confirm_url=confirm_url)
    subject = <span class="hljs-string">"Please confirm your email"</span>
    send_email(current_user.email, subject, html)
    flash(<span class="hljs-string">"A new confirmation email has been sent."</span>, <span class="hljs-string">"success"</span>)
    <span class="hljs-keyword">return</span> redirect(url_for(<span class="hljs-string">"accounts.inactive"</span>))
</code></pre>
<p>This code defines a route for the <code>resend_confirmation</code> view function in a Flask app. The route is decorated with the <code>login_required</code> decorator, which requires the user to be logged in to access the view.</p>
<p>The view function first checks if the user's account is already confirmed. If the account is confirmed, a message is displayed indicating that the account has already been confirmed and the user is redirected to the home page.</p>
<p>If the account is not confirmed, a token is generated as earlier. The <code>url_for</code> function is then called to generate a URL for the <code>confirm_email</code> route with the <code>token</code> as an argument. The <code>send_email</code> function is then called to send the email with the rendered template as the body, using the user's email address as the recipient and a subject of "Please confirm your email". A message is displayed indicating that a new confirmation email has been sent, and the user is redirected to the <code>inactive</code> view.</p>
<h3 id="heading-how-to-add-middleware-for-routes">How to add middleware for routes</h3>
<p>Now that you have the email verification mechanism ready, you want your routes in the <code>core</code> package to be accessed by only users with a confirmed account. To do that, you can add a decorator on those routes.</p>
<p>Create a new decorator in the <code>src/utils/decorators.py</code> file:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">check_is_confirmed</span>(<span class="hljs-params">func</span>):</span>
<span class="hljs-meta">    @wraps(func)</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">decorated_function</span>(<span class="hljs-params">*args, **kwargs</span>):</span>
        <span class="hljs-keyword">if</span> current_user.is_confirmed <span class="hljs-keyword">is</span> <span class="hljs-literal">False</span>:
            flash(<span class="hljs-string">"Please confirm your account!"</span>, <span class="hljs-string">"warning"</span>)
            <span class="hljs-keyword">return</span> redirect(url_for(<span class="hljs-string">"accounts.inactive"</span>))
        <span class="hljs-keyword">return</span> func(*args, **kwargs)

    <span class="hljs-keyword">return</span> decorated_function
</code></pre>
<p>This code defines a decorator called <code>check_is_confirmed</code>. The decorator takes a function as an argument and returns a decorated function.</p>
<p>The decorator works by checking if the user's account is confirmed. If the account is not confirmed, a message is displayed warning the user to confirm their account, and the user is redirected to the <code>inactive</code> view. If the account is confirmed, the decorated function is called as usual.</p>
<p>Now, you can use this decorator in the <code>home</code> view function in <code>src/core/views.py</code> file:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> src.utils.decorators <span class="hljs-keyword">import</span> check_is_confirmed


<span class="hljs-meta">@core_bp.route("/")</span>
<span class="hljs-meta">@login_required</span>
<span class="hljs-meta">@check_is_confirmed</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>This is how it looks when you login, and your account is not verified:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/Screenshot-2023-01-05-234723.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-how-to-add-new-test-cases">How to Add New Test Cases</h2>
<p>Now that you have added the main functionality, it's time to update the test suite.</p>
<h3 id="heading-how-to-modify-the-setup-method-in-basetestpy">How to modify the <code>setUp()</code> method in <code>base_test.py</code></h3>
<p>Replace the <code>setUp()</code> method with the following code:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">setUp</span>(<span class="hljs-params">self</span>):</span>
    db.create_all()
    unconfirmed_user = User(email=<span class="hljs-string">"unconfirmeduser@gmail.com"</span>,
                                password=<span class="hljs-string">"unconfirmeduser"</span>)
    db.session.add(unconfirmed_user)
    confirmed_user = User(email=<span class="hljs-string">"confirmeduser@gmail.com"</span>,
                              password=<span class="hljs-string">"confirmeduser"</span>, is_confirmed=<span class="hljs-literal">True</span>)
    db.session.add(confirmed_user)
    db.session.commit()
</code></pre>
<p>The method now creates two users – a user with a confirmed account and another user without a confirmed account.</p>
<p>Note that you'll need to replace the usage of the old email address and password with the unconfirmed user's email address and password in all the test files.</p>
<h3 id="heading-how-to-add-new-test-cases-in-testroutespy">How to add new test cases in <code>test_routes.py</code></h3>
<p>Since unauthenticated users cannot access the home page, let's add a test case in the <code>TestLoggingInOut</code> class to see if the user is redirected to the login page:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_home_route_requires_login</span>(<span class="hljs-params">self</span>):</span>
    self.client.get(<span class="hljs-string">"/logout"</span>, follow_redirects=<span class="hljs-literal">True</span>)
    self.client.get(<span class="hljs-string">'/'</span>, follow_redirects=<span class="hljs-literal">True</span>)
    self.assertTemplateUsed(<span class="hljs-string">'accounts/login.html'</span>)
</code></pre>
<p>Create a new <code>TestEmailConfirmationToken</code> class in the same file:</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TestEmailConfirmationToken</span>(<span class="hljs-params">BaseTestCase</span>):</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_confirm_token_route_requires_login</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-comment"># Ensure confirm/&lt;token&gt; route requires logged in user.</span>
        self.client.get(<span class="hljs-string">"/logout"</span>, follow_redirects=<span class="hljs-literal">True</span>)
        self.client.get(<span class="hljs-string">'/confirm/some-unique-id'</span>, follow_redirects=<span class="hljs-literal">True</span>)
        self.assertTemplateUsed(<span class="hljs-string">'accounts/login.html'</span>)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_confirm_token_route_valid_token</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-comment"># Ensure user can confirm account with valid token.</span>
        <span class="hljs-keyword">with</span> self.client:
            self.client.get(<span class="hljs-string">"/logout"</span>, follow_redirects=<span class="hljs-literal">True</span>)
            self.client.post(<span class="hljs-string">'/login'</span>, data=dict(
                email=<span class="hljs-string">'unconfirmeduser@gmail.com'</span>, password=<span class="hljs-string">'unconfirmeduser'</span>
            ), follow_redirects=<span class="hljs-literal">True</span>)
            token = generate_token(<span class="hljs-string">'unconfirmeduser@gmail.com'</span>)
            response = self.client.get(
                <span class="hljs-string">'/confirm/'</span>+token, follow_redirects=<span class="hljs-literal">True</span>)
            self.assertIn(
                <span class="hljs-string">b'You have confirmed your account. Thanks!'</span>, response.data)
            self.assertTemplateUsed(<span class="hljs-string">'core/index.html'</span>)
            user = User.query.filter_by(
                email=<span class="hljs-string">'unconfirmeduser@gmail.com'</span>).first_or_404()
            self.assertIsInstance(user.confirmed_on, datetime)
            self.assertTrue(user.is_confirmed)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_confirm_token_route_invalid_token</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-comment"># Ensure user cannot confirm account with invalid token.</span>
        token = generate_token(<span class="hljs-string">'test@test1.com'</span>)
        <span class="hljs-keyword">with</span> self.client:
            self.client.get(<span class="hljs-string">"/logout"</span>, follow_redirects=<span class="hljs-literal">True</span>)
            self.client.post(<span class="hljs-string">'/login'</span>, data=dict(
                email=<span class="hljs-string">'unconfirmeduser@gmail.com'</span>, password=<span class="hljs-string">'unconfirmeduser'</span>
            ), follow_redirects=<span class="hljs-literal">True</span>)
            response = self.client.get(<span class="hljs-string">'/confirm/'</span>+token,
                                       follow_redirects=<span class="hljs-literal">True</span>)
            self.assertIn(
                <span class="hljs-string">b'The confirmation link is invalid or has expired.'</span>,
                response.data
            )

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_confirm_token_route_expired_token</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-comment"># Ensure user cannot confirm account with expired token.</span>
        user = User(email=<span class="hljs-string">'test@test1.com'</span>, password=<span class="hljs-string">'test1'</span>)
        db.session.add(user)
        db.session.commit()
        token = generate_token(<span class="hljs-string">'test@test1.com'</span>)
        self.assertFalse(confirm_token(token, <span class="hljs-number">-1</span>))
</code></pre>
<p>The above code tests the email verification functionality of the app.</p>
<ul>
<li>The <code>test_confirm_token_route_requires_login</code> test case tests that when a user tries to access the confirmation route when not logged in, they are redirected to the login page.</li>
<li>The <code>test_confirm_token_route_valid_token</code> test case tests that when a user tries to access the confirmation route with a valid token, their account is confirmed and they are redirected to the index page.</li>
<li>The <code>test_confirm_token_route_invalid_token</code> test case tests that when a user tries to access the confirmation route with an invalid token, an error message is displayed.</li>
<li>The <code>test_confirm_token_route_expired_token</code> test case tests that when a user tries to access the confirmation route with an expired token, an error message is displayed.</li>
</ul>
<h2 id="heading-wrapping-up"><strong>Wrapping up</strong></h2>
<p>In this tutorial, you learned how to handle email verification in your Flask app. You also wrote few more testcases in order to test the new functionalities.</p>
<p>Here's the link to the <a target="_blank" href="https://github.com/ashutoshkrris/Flask-User-Authentication-With-Email-Verification">GitHub repository</a>. Feel free to check it out whenever you're stuck.</p>
<h3 id="heading-recommended-next-steps"><strong>Recommended next steps</strong></h3>
<ul>
<li>You can add a "forgot password" feature in the application.</li>
<li>You can allow users to manage their profiles.</li>
<li>You can add more testcases in order to test the app more thoroughly.</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 Set Up Basic User Authentication in a Flask App ]]>
                </title>
                <description>
                    <![CDATA[ User authentication is important for protecting sensitive information and resources from unauthorized access. It helps ensure that only authorized users can access and make changes to data, and helps prevent unauthorized users from gaining access to ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-setup-user-authentication-in-flask/</link>
                <guid isPermaLink="false">66ba0e9f228e16bed602a894</guid>
                
                    <category>
                        <![CDATA[ authentication ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Flask Framework ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ashutosh Krishna ]]>
                </dc:creator>
                <pubDate>Tue, 03 Jan 2023 14:57:06 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/12/basic-auth.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>User authentication is important for protecting sensitive information and resources from unauthorized access. It helps ensure that only authorized users can access and make changes to data, and helps prevent unauthorized users from gaining access to sensitive information.</p>
<p>There are different methods for implementing user authentication, including password-based authentication, token-based authentication, and so on. </p>
<p>In this tutorial, you will learn how to set up basic user authentication – that is password-based authentication – in your Flask application.</p>
<h2 id="heading-project-demo">Project Demo</h2>
<p>Here’s what the final output will look like:</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/XxSESg89xEI" 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>The link to the GitHub repository is available at the end of the tutorial. Feel free to check it out whenever you're stuck.</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>
</ul>
<h2 id="heading-get-your-tools-ready">Get Your Tools Ready</h2>
<p>You'll need a few external libraries in 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-basic-auth
ccd flask-basic-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://pythonhosted.org/Flask-Testing/">Flask-Testing</a> extension provides unit testing utilities for Flask.</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, run the following command:</p>
<pre><code class="lang-bash">pip install Flask Flask-Login Flask-Bcrypt Flask-WTF FLask-Migrate Flask-SQLAlchemy Flask-Testing python-decouple
</code></pre>
<blockquote>
<p>This tutorial was verified with Python V3.11, Flask V2.2.2, Flask-Login V0.6.0, Flask-Bcrypt V1.0.1, Flask-WTF V1.0.1, Flask-SQLAlchemy V2.5.1 and, Flask-Testing V0.8.1.</p>
</blockquote>
<h2 id="heading-how-to-set-up-the-project">How to Set Up the Project</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. You also set the configuration of the app using an environment variable called <code>APP_SETTINGS</code>. You'll export it later.</p>
<p>To use Flask-Bcrypt, Flask-SQLAlchemy, and Flask-Migrate in your application, you 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>You've also registered blueprints called <code>accounts_bp</code> and <code>core_bp</code> in the application. You'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>


<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> and <code>DATABASE_URL</code>. Create a file named <code>.env</code> in the root directory and add the following content there:</p>
<pre><code><span class="hljs-keyword">export</span> SECRET_KEY=fdkjshfhjsdfdskfdsfdcbsjdkfdsdf
<span class="hljs-keyword">export</span> DEBUG=True
<span class="hljs-keyword">export</span> APP_SETTINGS=config.DevelopmentConfig
<span class="hljs-keyword">export</span> DATABASE_URL=sqlite:<span class="hljs-comment">///db.sqlite</span>
<span class="hljs-keyword">export</span> FLASK_APP=src
<span class="hljs-keyword">export</span> FLASK_DEBUG=<span class="hljs-number">1</span>
</code></pre><p>Apart from the <code>SECRET_KEY</code> and <code>DATABASE_URL</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, you'll create a CLI application of the app so that you can later add custom commands such as <code>test</code> and <code>create_admin</code> in order to test the application and create admin, respectively. </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>
<h2 id="heading-how-to-create-blueprints-for-accounts-and-core">How to Create Blueprints for Accounts and Core</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>
<h2 id="heading-how-to-create-a-user-model">How to Create a User Model</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">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">db.Model</span>):</span>

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

    id = db.Column(db.Integer, primary_key=<span class="hljs-literal">True</span>)
    email = 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_on = db.Column(db.DateTime, nullable=<span class="hljs-literal">False</span>)
    is_admin = db.Column(db.Boolean, nullable=<span class="hljs-literal">False</span>, default=<span class="hljs-literal">False</span>)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, email, password, is_admin=False</span>):</span>
        self.email = email
        self.password = bcrypt.generate_password_hash(password)
        self.created_on = datetime.now()
        self.is_admin = is_admin

    <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;email <span class="hljs-subst">{self.email}</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>email</code>: stores the email of the user</li>
<li><code>password</code>: stores the hashed password of the user</li>
<li><code>created_on</code>: stores the timestamp when the user was created</li>
<li><code>is_admin</code>: stores whether the user is admin or not</li>
</ul>
<p>In the constructor of the class, you set the fields. Notice the password field where you generate the hash of the password using the <code>bcrypt</code> object imported from the app. </p>
<h2 id="heading-how-to-add-flask-login">How to Add Flask-Login</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, you created and initialized the login manager in your app.</p>
<p>Next, you 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, you 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. You 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>

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

    id = db.Column(db.Integer, primary_key=<span class="hljs-literal">True</span>)
    email = 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_on = db.Column(db.DateTime, nullable=<span class="hljs-literal">False</span>)
    is_admin = db.Column(db.Boolean, nullable=<span class="hljs-literal">False</span>, default=<span class="hljs-literal">False</span>)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, email, password, is_admin=False</span>):</span>
        self.email = email
        self.password = bcrypt.generate_password_hash(password)
        self.created_on = datetime.now()
        self.is_admin = is_admin

    <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;email <span class="hljs-subst">{self.email}</span>&gt;"</span>
</code></pre>
<p>You 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">How to Add Templates and Static Files</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>Flask User Management<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.2.0/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-gH2yIJqKdNHPEq0n4Mqa/HGKIhSkIHeL5AyhkYV8i59U5AR6csBvApHHNl/vI1Bx"</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.6.1.min.js"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text/javascript"</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/bootstrap@5.2.0/dist/js/bootstrap.bundle.min.js"</span> <span class="hljs-attr">integrity</span>=<span class="hljs-string">"sha384-A3rJD856KowSb7dwlZdYEkO39Gagi7vIsF0jrRAoQmDKKtQBHUuLZ9AsSv4jD4Xa"</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">header</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"p-3 text-bg-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"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"d-flex flex-wrap align-items-center justify-content-center justify-content-lg-start"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"nav col-12 col-lg-auto me-lg-auto mb-2 justify-content-center mb-md-0"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"{{ url_for('core.home') }}"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"nav-link px-2 text-secondary"</span>&gt;</span>Home<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span><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-end"</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>
        {% else %}
          <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><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-outline-light me-2"</span>&gt;</span>Login<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>
          <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><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-success"</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">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">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">header</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">How to Create the Homepage</h2>
<p>In this section, you'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 from 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.email}}!<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>
<h2 id="heading-how-to-implement-user-registration">How to Implement User Registration</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>
    email = EmailField(
        <span class="hljs-string">"Email"</span>, validators=[DataRequired(), Email(message=<span class="hljs-literal">None</span>), 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</span>):</span>
        initial_validation = super(RegisterForm, self).validate()
        <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(email=self.email.data).first()
        <span class="hljs-keyword">if</span> user:
            self.email.errors.append(<span class="hljs-string">"Email 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>email</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>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> flask <span class="hljs-keyword">import</span> Blueprint, flash, redirect, render_template, request, url_for
<span class="hljs-keyword">from</span> flask_login <span class="hljs-keyword">import</span> login_user

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

<span class="hljs-keyword">from</span> .forms <span class="hljs-keyword">import</span> RegisterForm


<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:
        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(<span class="hljs-string">"core.home"</span>))
    form = RegisterForm(request.form)
    <span class="hljs-keyword">if</span> form.validate_on_submit():
        user = User(email=form.email.data, password=form.password.data)
        db.session.add(user)
        db.session.commit()

        login_user(user)
        flash(<span class="hljs-string">"You registered and are now logged in. Welcome!"</span>, <span class="hljs-string">"success"</span>)

        <span class="hljs-keyword">return</span> redirect(url_for(<span class="hljs-string">"core.home"</span>))

    <span class="hljs-keyword">return</span> render_template(<span class="hljs-string">"accounts/register.html"</span>, form=form)
</code></pre>
<p>In the above function, notice that we're using the blueprint to add the route for the function. Initially, we check if a user is already authenticated using the <code>is_authenticated</code> property. If it is, we redirect it to the homepage with a message.</p>
<p>If no user is authenticated, we first create an instance of the <code>RegisterForm</code> class. If the request method is GET, we render an HTML file with the form. Otherwise, we check if the form has valid inputs using the <code>validate_on_submit()</code> method. </p>
<p>If the inputs are valid, we create an instance of the <code>User</code> class with the email and password provided by the user, and add it to the database. </p>
<p>Next, we login the user using the <code>login_user()</code> method that accepts the <code>user</code> object. We also flash a success message and redirect the user to the homepage.</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.email(placeholder="email", class="form-control mb-2") }}
          {{ form.email.label }}
            {% if form.email.errors %}
              {% for error in form.email.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 code, we created an HTML form where we make use of the <code>form</code> instance that contains the form fields with their labels and errors. We have used a <code>accounts.login</code> view function which doesn't exist yet.</p>
<h2 id="heading-how-to-implement-user-login-and-logout">How to Implement User Login and Logout</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>
    email = EmailField(<span class="hljs-string">"Email"</span>, validators=[DataRequired(), Email()])
    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>email</code> and <code>password</code>.</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> flask <span class="hljs-keyword">import</span> Blueprint, flash, redirect, render_template, request, url_for
<span class="hljs-keyword">from</span> flask_login <span class="hljs-keyword">import</span> login_user

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

<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:
        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(<span class="hljs-string">"core.home"</span>))
    form = LoginForm(request.form)
    <span class="hljs-keyword">if</span> form.validate_on_submit():
        user = User.query.filter_by(email=form.email.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">return</span> redirect(url_for(<span class="hljs-string">"core.home"</span>))
        <span class="hljs-keyword">else</span>:
            flash(<span class="hljs-string">"Invalid email 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)
    <span class="hljs-keyword">return</span> render_template(<span class="hljs-string">"accounts/login.html"</span>, form=form)
</code></pre>
<p>Similar to registration view function, we first check if a user is already authenticated using the <code>is_authenticated</code> property. If it is, we redirect it to the homepage with a message.</p>
<p>If not authenticated, we create an instance of the login form. If the request method is GET, we simply render a <code>login.html</code> file with the form. Otherwise, the form is validated. </p>
<p>During the validation, we use the <code>check_password_hash</code> method from the <code>Flask-Bcrypt</code> library to match the hashed passwords. If the passwords match, we login the user using the <code>login_user()</code> method and redirect to the homepage. Otherwise, we flash an error message and render the same HTML page.</p>
<p>Now, let's create a <code>login.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>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.email(placeholder="email", class="form-control mb-2") }}
          {{ form.email.label }}
            {% if form.email.errors %}
              {% for error in form.email.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 login form is similar to the registration form but with just two fields for the email and password.</p>
<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-run-the-completed-app-for-the-first-time">How to Run the Completed App for the First Time</h2>
<p>Now that your application is ready (without the tests), you can first migrate the database, and then run the app.</p>
<ul>
<li>To initialize the database (create a migration repository), use the command:</li>
</ul>
<pre><code class="lang-bash">flask db init
</code></pre>
<ul>
<li>To migrate the database changes, use the command:</li>
</ul>
<pre><code class="lang-bash">flask db migrate
</code></pre>
<ul>
<li>To apply the migrations, use the command:</li>
</ul>
<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><h2 id="heading-how-to-add-unit-tests-to-the-app">How to Add Unit Tests to the App</h2>
<p>Now that we have all the features ready, create a <code>tests</code> folder in the root directory and convert it into a package by adding an empty <code>__init__.py</code> file.</p>
<h3 id="heading-how-to-create-a-base-testcase">How to Create a Base TestCase</h3>
<p>Let's create a base testcase that will be extended by the other testcases. Create a <code>base_test.py</code> file inside the <code>tests</code> package, and add the following code:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> os

<span class="hljs-keyword">from</span> flask_testing <span class="hljs-keyword">import</span> TestCase

<span class="hljs-keyword">from</span> src <span class="hljs-keyword">import</span> app, db
<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">BaseTestCase</span>(<span class="hljs-params">TestCase</span>):</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">create_app</span>(<span class="hljs-params">self</span>):</span>
        app.config.from_object(<span class="hljs-string">"config.TestingConfig"</span>)
        <span class="hljs-keyword">return</span> app

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">setUp</span>(<span class="hljs-params">self</span>):</span>
        db.create_all()
        user = User(email=<span class="hljs-string">"ad@min.com"</span>, password=<span class="hljs-string">"admin_user"</span>)
        db.session.add(user)
        db.session.commit()

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">tearDown</span>(<span class="hljs-params">self</span>):</span>
        db.session.remove()
        db.drop_all()
        testdb_path = os.path.join(<span class="hljs-string">"src"</span>, <span class="hljs-string">"testdb.sqlite"</span>)
        os.remove(testdb_path)
</code></pre>
<p>The <code>BaseTestCase</code> class extends the <code>TestCase</code> class and implements the following three methods:</p>
<ul>
<li>The <code>create_app()</code> method is a required method which should return a Flask instance. If you don’t define <code>create_app()</code>,  <code>NotImplementedError</code> will be raised. Notice that we're using the <code>TestingConfig</code> in this case.</li>
<li>The <code>setUp()</code> method is called before running any test. In this method, we create all the database tables. Additionally, we also create a user so that we can play with it later.</li>
<li>The <code>tearDown()</code> method is called after running all the testcases. So, in this method, we'll clean up all the test data.</li>
</ul>
<h3 id="heading-how-to-write-tests-for-forms">How to Write Tests for Forms</h3>
<p>In the above sections, we created two forms – <code>RegisterForm</code> and <code>LoginForm</code>. Let's test these forms in a new test file named <code>test_forms.py</code> inside the <code>tests</code> package.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> unittest

<span class="hljs-keyword">from</span> base_test <span class="hljs-keyword">import</span> BaseTestCase

<span class="hljs-keyword">from</span> src.accounts.forms <span class="hljs-keyword">import</span> LoginForm, RegisterForm


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TestRegisterForm</span>(<span class="hljs-params">BaseTestCase</span>):</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_validate_success_register_form</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-comment"># Ensure correct data validates.</span>
        form = RegisterForm(email=<span class="hljs-string">"new@test.com"</span>, password=<span class="hljs-string">"example"</span>, confirm=<span class="hljs-string">"example"</span>)
        self.assertTrue(form.validate())

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_validate_invalid_password_format</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-comment"># Ensure incorrect data does not validate.</span>
        form = RegisterForm(email=<span class="hljs-string">"new@test.com"</span>, password=<span class="hljs-string">"example"</span>, confirm=<span class="hljs-string">""</span>)
        self.assertFalse(form.validate())

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_validate_email_already_registered</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-comment"># Ensure user can't register when a duplicate email is used</span>
        form = RegisterForm(
            email=<span class="hljs-string">"ad@min.com"</span>, password=<span class="hljs-string">"admin_user"</span>, confirm=<span class="hljs-string">"admin_user"</span>
        )
        self.assertFalse(form.validate())


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TestLoginForm</span>(<span class="hljs-params">BaseTestCase</span>):</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_validate_success_login_form</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-comment"># Ensure correct data validates.</span>
        form = LoginForm(email=<span class="hljs-string">"ad@min.com"</span>, password=<span class="hljs-string">"admin_user"</span>)
        self.assertTrue(form.validate())

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_validate_invalid_email_format</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-comment"># Ensure invalid email format throws error.</span>
        form = LoginForm(email=<span class="hljs-string">"unknown"</span>, password=<span class="hljs-string">"example"</span>)
        self.assertFalse(form.validate())


<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>:
    unittest.main()
</code></pre>
<p>The <code>TestRegisterForm</code> class defines three test methods to test the <code>validate</code> method of the <code>RegisterForm</code> class. </p>
<p>The first test method tests that the form validates with correct input data. The second test method tests that the form does not validate with an invalid password format. And the third test method tests that the form does not validate when a duplicate email is used to register.</p>
<p>The <code>TestLoginForm</code> class defines two test methods to test the <code>validate</code> method of the <code>LoginForm</code> class. The first test method tests that the form validates with correct input data, and the second test method tests that the form does not validate with an invalid email format.</p>
<h3 id="heading-how-to-test-the-user-model">How to Test the User Model</h3>
<p>Let's now test the <code>User</code> model in a new file named <code>test_models.py</code> inside the <code>tests</code> package.</p>
<pre><code class="lang-py"><span class="hljs-keyword">import</span> datetime
<span class="hljs-keyword">import</span> unittest

<span class="hljs-keyword">from</span> base_test <span class="hljs-keyword">import</span> BaseTestCase
<span class="hljs-keyword">from</span> flask_login <span class="hljs-keyword">import</span> current_user

<span class="hljs-keyword">from</span> src <span class="hljs-keyword">import</span> bcrypt
<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">TestUser</span>(<span class="hljs-params">BaseTestCase</span>):</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_user_registration</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-comment"># Ensure user registration behaves correctly.</span>
        <span class="hljs-keyword">with</span> self.client:
            self.client.get(<span class="hljs-string">"/logout"</span>, follow_redirects=<span class="hljs-literal">True</span>)
            self.client.post(
                <span class="hljs-string">"/register"</span>,
                data=dict(
                    email=<span class="hljs-string">"test@user.com"</span>, password=<span class="hljs-string">"test_user"</span>, confirm=<span class="hljs-string">"test_user"</span>
                ),
                follow_redirects=<span class="hljs-literal">True</span>,
            )
            user = User.query.filter_by(email=<span class="hljs-string">"test@user.com"</span>).first()
            self.assertTrue(user.id)
            self.assertTrue(user.email == <span class="hljs-string">"test@user.com"</span>)
            self.assertFalse(user.is_admin)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_get_by_id</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-comment"># Ensure id is correct for the current/logged in user</span>
        <span class="hljs-keyword">with</span> self.client:
            self.client.get(<span class="hljs-string">"/logout"</span>, follow_redirects=<span class="hljs-literal">True</span>)
            self.client.post(
                <span class="hljs-string">"/login"</span>,
                data=dict(email=<span class="hljs-string">"ad@min.com"</span>, password=<span class="hljs-string">"admin_user"</span>),
                follow_redirects=<span class="hljs-literal">True</span>,
            )
            self.assertTrue(current_user.id == <span class="hljs-number">1</span>)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_created_on_defaults_to_datetime</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-comment"># Ensure that registered_on is a datetime</span>
        <span class="hljs-keyword">with</span> self.client:
            self.client.get(<span class="hljs-string">"/logout"</span>, follow_redirects=<span class="hljs-literal">True</span>)
            self.client.post(
                <span class="hljs-string">"/login"</span>,
                data=dict(email=<span class="hljs-string">"ad@min.com"</span>, password=<span class="hljs-string">"admin_user"</span>),
                follow_redirects=<span class="hljs-literal">True</span>,
            )
            user = User.query.filter_by(email=<span class="hljs-string">"ad@min.com"</span>).first()
            self.assertIsInstance(user.created_on, datetime.datetime)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_check_password</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-comment"># Ensure given password is correct after unhashing</span>
        user = User.query.filter_by(email=<span class="hljs-string">"ad@min.com"</span>).first()
        self.assertTrue(bcrypt.check_password_hash(user.password, <span class="hljs-string">"admin_user"</span>))
        self.assertFalse(bcrypt.check_password_hash(user.password, <span class="hljs-string">"foobar"</span>))

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_validate_invalid_password</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-comment"># Ensure user can't login when the pasword is incorrect</span>
        <span class="hljs-keyword">with</span> self.client:
            self.client.get(<span class="hljs-string">"/logout"</span>, follow_redirects=<span class="hljs-literal">True</span>)
            response = self.client.post(
                <span class="hljs-string">"/login"</span>,
                data=dict(email=<span class="hljs-string">"ad@min.com"</span>, password=<span class="hljs-string">"foo_bar"</span>),
                follow_redirects=<span class="hljs-literal">True</span>,
            )
        self.assertIn(<span class="hljs-string">b"Invalid email and/or password."</span>, response.data)


<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>:
    unittest.main()
</code></pre>
<p>The <code>TestUser</code> class defines four test methods to test various aspects of the <code>User</code> model class. </p>
<ul>
<li>The first test method tests the user registration process by posting a registration request to the server with the <code>client</code> object, which is a Flask test client. The test verifies that a new user is correctly added to the database and that the user's attributes are correctly set.</li>
<li>The second test method tests the <code>get_by_id</code> method, which is a helper method to get the user object from the database by its id. The test logs in a user and verifies that the current user's id is correct.</li>
<li>The third test method tests that the <code>created_on</code> attribute of the user object is a datetime object.</li>
<li>The fourth test method tests the <code>check_password</code> method, which is a helper method to check the user's password. The test verifies that the method correctly checks a correct and an incorrect password.</li>
<li>The fifth test method tests the login process by posting a login request to the server with the <code>client</code> object and verifies that the server responds with an error message when the password is incorrect.</li>
</ul>
<h3 id="heading-how-to-test-the-routes">How to Test the Routes</h3>
<p>Let's now test the routes in a new file named <code>test_routes.py</code> inside the <code>tests</code> package.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> unittest

<span class="hljs-keyword">from</span> base_test <span class="hljs-keyword">import</span> BaseTestCase
<span class="hljs-keyword">from</span> flask_login <span class="hljs-keyword">import</span> current_user


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TestPublic</span>(<span class="hljs-params">BaseTestCase</span>):</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_main_route_requires_login</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-comment"># Ensure main route requres logged in user.</span>
        response = self.client.get(<span class="hljs-string">"/"</span>, follow_redirects=<span class="hljs-literal">True</span>)
        self.assertTrue(response.status_code == <span class="hljs-number">200</span>)
        self.assertIn(<span class="hljs-string">b"Please log in to access this page"</span>, response.data)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_logout_route_requires_login</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-comment"># Ensure logout route requres logged in user.</span>
        response = self.client.get(<span class="hljs-string">"/logout"</span>, follow_redirects=<span class="hljs-literal">True</span>)
        self.assertIn(<span class="hljs-string">b"Please log in to access this page"</span>, response.data)


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TestLoggingInOut</span>(<span class="hljs-params">BaseTestCase</span>):</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_correct_login</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-comment"># Ensure login behaves correctly with correct credentials</span>
        <span class="hljs-keyword">with</span> self.client:
            response = self.client.post(
                <span class="hljs-string">"/login"</span>,
                data=dict(email=<span class="hljs-string">"ad@min.com"</span>, password=<span class="hljs-string">"admin_user"</span>),
                follow_redirects=<span class="hljs-literal">True</span>,
            )
            self.assertTrue(current_user.email == <span class="hljs-string">"ad@min.com"</span>)
            self.assertTrue(current_user.is_active)
            self.assertTrue(response.status_code == <span class="hljs-number">200</span>)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_logout_behaves_correctly</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-comment"># Ensure logout behaves correctly, regarding the session</span>
        <span class="hljs-keyword">with</span> self.client:
            self.client.post(
                <span class="hljs-string">"/login"</span>,
                data=dict(email=<span class="hljs-string">"ad@min.com"</span>, password=<span class="hljs-string">"admin_user"</span>),
                follow_redirects=<span class="hljs-literal">True</span>,
            )
            response = self.client.get(<span class="hljs-string">"/logout"</span>, follow_redirects=<span class="hljs-literal">True</span>)
            self.assertIn(<span class="hljs-string">b"You were logged out."</span>, response.data)
            self.assertFalse(current_user.is_active)


<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>:
    unittest.main()
</code></pre>
<p>The <code>TestPublic</code> class defines two test methods to test the access control of certain routes. </p>
<p>The first test method tests that the main route requires a logged-in user by attempting to access it with the <code>client</code> object, which is a Flask test client. The test verifies that the server responds with a login prompt. The second test method tests that the logout route also requires a logged-in user.</p>
<p>The <code>TestLoggingInOut</code> class defines two test methods to test the login and logout functionality. </p>
<p>The first test method tests the login process by posting a login request to the server with the <code>client</code> object and verifies that the server responds with a successful login. The second test method tests the logout process by posting a logout request to the server with the <code>client</code> object. It then verifies that the server responds with a logout message and that the user is no longer logged in.</p>
<h3 id="heading-how-to-run-the-tests">How to Run the Tests</h3>
<p>Now that we have all the tests ready, we are ready to run the testcases. But before that, as mentioned in the beginning, we'll need to add a command in the <code>manage.py</code> file to run the tests.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> unittest


<span class="hljs-meta">@cli.command("test")</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test</span>():</span>
    <span class="hljs-string">"""Runs the unit tests without coverage."""</span>
    tests = unittest.TestLoader().discover(<span class="hljs-string">"tests"</span>)
    result = unittest.TextTestRunner(verbosity=<span class="hljs-number">2</span>).run(tests)
    <span class="hljs-keyword">if</span> result.wasSuccessful():
        <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>
    <span class="hljs-keyword">else</span>:
        <span class="hljs-keyword">return</span> <span class="hljs-number">1</span>
</code></pre>
<p>The command runs the unit tests in the <code>tests</code> package and displays the results in the terminal.</p>
<p>You use the <code>unittest.TestLoader().discover()</code> method to discover and run all the unit tests in the <code>tests</code> package. You use the <code>unittest.TextTestRunner()</code> method to run the unit tests and to print the results to the terminal. The <code>verbosity</code> argument controls the level of detail in the output.</p>
<p>If all the unit tests pass, the <code>test</code> command returns a exit code of 0. If any of the unit tests fail, the command returns a exit code of 1.</p>
<p>Now, you can run all the tests using the command:</p>
<pre><code class="lang-bash">python manage.py <span class="hljs-built_in">test</span>
</code></pre>
<p>This will give the below output:</p>
<pre><code class="lang-bash">test_validate_invalid_email_format (test_forms.TestLoginForm) ... ok
test_validate_success_login_form (test_forms.TestLoginForm) ... ok
test_validate_email_already_registered (test_forms.TestRegisterForm) ... ok
test_validate_invalid_password_format (test_forms.TestRegisterForm) ... ok
test_validate_success_register_form (test_forms.TestRegisterForm) ... ok
test_check_password (test_models.TestUser) ... ok
test_created_on_defaults_to_datetime (test_models.TestUser) ... ok
test_get_by_id (test_models.TestUser) ... ok
test_user_registration (test_models.TestUser) ... ok
test_validate_invalid_password (test_models.TestUser) ... ok
test_correct_login (test_routes.TestLoggingInOut) ... ok
test_logout_behaves_correctly (test_routes.TestLoggingInOut) ... ok
test_logout_route_requires_login (test_routes.TestPublic) ... ok
test_main_route_requires_login (test_routes.TestPublic) ... ok

----------------------------------------------------------------------
Ran 14 tests <span class="hljs-keyword">in</span> 19.577s

OK
</code></pre>
<h2 id="heading-features-to-add-to-your-application">Features to Add to Your Application</h2>
<p>Here are some extra things you can add in your application. Note that these are optional.</p>
<h3 id="heading-how-to-create-an-admin">How to Create an Admin</h3>
<p>Similar to the <code>test</code> command, you can add a <code>create_admin</code> command to create an admin in your application. Add the following code inside the <code>manage.py</code> file:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> getpass


<span class="hljs-meta">@cli.command("create_admin")</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">create_admin</span>():</span>
    <span class="hljs-string">"""Creates the admin user."""</span>
    email = input(<span class="hljs-string">"Enter email address: "</span>)
    password = getpass.getpass(<span class="hljs-string">"Enter password: "</span>)
    confirm_password = getpass.getpass(<span class="hljs-string">"Enter password again: "</span>)
    <span class="hljs-keyword">if</span> password != confirm_password:
        print(<span class="hljs-string">"Passwords don't match"</span>)
        <span class="hljs-keyword">return</span> <span class="hljs-number">1</span>
    <span class="hljs-keyword">try</span>:
        user = User(email=email, password=password, is_admin=<span class="hljs-literal">True</span>)
        db.session.add(user)
        db.session.commit()
    <span class="hljs-keyword">except</span> Exception:
        print(<span class="hljs-string">"Couldn't create admin user."</span>)
</code></pre>
<p>The command prompts the user to enter an email address and a password for the admin user. The password is entered using the <code>getpass</code> module, which hides the password input from the terminal. The command then checks if the entered password and the confirmed password match. If the passwords don't match, the command prints an error message and returns a exit code of 1.</p>
<p>If the passwords match, the command creates a new <code>User</code> object with the entered email address, password, and the <code>is_admin</code> attribute set to <code>True</code>. The command then adds the user object to the database session and commits the changes to the database. If an exception is raised during this process, the command prints an error message.</p>
<p>You can run the below command to create one:</p>
<pre><code class="lang-bash">python manage.py create_admin
</code></pre>
<p>Output:</p>
<pre><code class="lang-bash">&gt; python manage.py create_admin
Enter email address: admin@myapp.com
Enter password: 
Enter password again: 
Admin with email admin@myapp.com created successfully!
</code></pre>
<h3 id="heading-how-to-create-error-pages">How to Create Error Pages</h3>
<p>Our application can get errors at any time. The most common errors that we get are Unauthorized (401), Not Found (404) and Server Error (500). </p>
<p>Let's create an <code>errors</code> directory inside the <code>templates</code> directory and create three HTML pages as below:</p>
<ul>
<li>401.html</li>
</ul>
<pre><code class="lang-html">{% extends "_base.html" %}
{% block content %}
<span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>401<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Run along!<span class="hljs-tag">&lt;/<span class="hljs-name">p</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">em</span>&gt;</span>Return <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"{{url_for('core.home')}}"</span>&gt;</span>Home<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>?<span class="hljs-tag">&lt;/<span class="hljs-name">em</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
{% endblock %}
</code></pre>
<ul>
<li>404.html</li>
</ul>
<pre><code class="lang-html">{% extends "_base.html" %}
{% block content %}
<span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>404<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>There's nothing here!<span class="hljs-tag">&lt;/<span class="hljs-name">p</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">em</span>&gt;</span>Return <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"{{url_for('core.home')}}"</span>&gt;</span>Home<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>?<span class="hljs-tag">&lt;/<span class="hljs-name">em</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
{% endblock %}
</code></pre>
<ul>
<li>500.html</li>
</ul>
<pre><code class="lang-html">{% extends "_base.html" %}
{% block content %}
<span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>500<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Something's wrong! We are on the job.<span class="hljs-tag">&lt;/<span class="hljs-name">p</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">em</span>&gt;</span>Return <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"{{url_for('core.home')}}"</span>&gt;</span>Home<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>?<span class="hljs-tag">&lt;/<span class="hljs-name">em</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
{% endblock %}
</code></pre>
<p>Next, we need to add error handlers for these errors. Open the <code>src/__init__.py</code> file and add the following code in the bottom of the file:</p>
<pre><code class="lang-python"><span class="hljs-meta">@app.errorhandler(401)</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">unauthorized_page</span>(<span class="hljs-params">error</span>):</span>
    <span class="hljs-keyword">return</span> render_template(<span class="hljs-string">"errors/401.html"</span>), <span class="hljs-number">401</span>


<span class="hljs-meta">@app.errorhandler(404)</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">page_not_found</span>(<span class="hljs-params">error</span>):</span>
    <span class="hljs-keyword">return</span> render_template(<span class="hljs-string">"errors/404.html"</span>), <span class="hljs-number">404</span>


<span class="hljs-meta">@app.errorhandler(500)</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">server_error_page</span>(<span class="hljs-params">error</span>):</span>
    <span class="hljs-keyword">return</span> render_template(<span class="hljs-string">"errors/500.html"</span>), <span class="hljs-number">500</span>
</code></pre>
<p>This above code snippet registers error handler functions for the HTTP error codes 401, 404, and 500 in a Flask application. An error handler function is a function that is called when an error occurs in the application.</p>
<p>The error handler functions are decorated with the <code>@app.errorhandler</code> decorator, which registers them with the Flask application. The decorator takes an error code as an argument, and the function is called when the error code is raised.</p>
<p>Each error handler function returns a rendered template and the error code as a response to the client. The templates are HTML files located in the <code>errors</code> folder and contain the content to be displayed to the user for each error. The error code is passed as an argument to the <code>render_template</code> function to determine which template to render.</p>
<h2 id="heading-wrapping-up">Wrapping up</h2>
<p>In this tutorial, you learned how to set up basic user authentication in your Flask app. You also wrote few testcases in order to test the functionalities.</p>
<p>Here's the link to the <a target="_blank" href="https://github.com/ashutoshkrris/Flask-User-Authentication">GitHub repository</a>. Feel free to check it out whenever you're stuck.</p>
<h3 id="heading-recommended-next-steps">Recommended next steps</h3>
<ul>
<li>You can add more security such as email verification, or token-based authentication in the app.</li>
<li>You can add a "forgot password" feature in the application.</li>
<li>You can add more testcases in order to test the app more thoroughly.</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 Use Blueprints to Organize Your Flask Apps ]]>
                </title>
                <description>
                    <![CDATA[ Flask is a simple, easy-to-use microframework for Python that can help you build scalable and secure web applications.  Sometimes you'll find developers dumping all of their logic into a single file called app.py. You will find a lot of tutorials tha... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-blueprints-to-organize-flask-apps/</link>
                <guid isPermaLink="false">66ba0ea2102ebf67c0a6d42f</guid>
                
                    <category>
                        <![CDATA[ Flask Framework ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ashutosh Krishna ]]>
                </dc:creator>
                <pubDate>Thu, 01 Sep 2022 15:25:10 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/09/blueprints.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Flask is a simple, easy-to-use microframework for Python that can help you build scalable and secure web applications. </p>
<p>Sometimes you'll find developers dumping all of their logic into a single file called app.py. You will find a lot of tutorials that follow the same pattern. But it's not a good practice for a large-scale app. </p>
<p>By doing this, you are clearly violating the <em>Single Responsibility Principle</em>, where each piece of your application should handle just one responsibility. </p>
<p>If you have worked with Django, you might have found your project divided into different modules. In Flask, also, you can organize your applications using <strong>Blueprints</strong>, a built-in concept in Flask similar to Python modules. </p>
<h2 id="heading-what-does-a-flask-application-look-like">What Does a Flask Application Look Like?</h2>
<p>If you follow the Flask documentation to create a minimal application, your project structure will look similar to this:</p>
<pre><code class="lang-md">/myapp
├── /templates
├── /static
└── app.py
</code></pre>
<p>Doesn't the folder look so clean? All you have is an <code>app.py</code> file where you have all your logic for the application, a <code>templates</code> folder to store your HTML files, and a <code>static</code> folder to store your static files. </p>
<p>Let's look at the app.py file:</p>
<pre><code class="lang-py"><span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> Flask


app = Flask(__name__)

<span class="hljs-comment"># Some Models Here</span>


<span class="hljs-comment"># Routes related to core functionalities</span>


<span class="hljs-comment"># Routes related to Profile Page</span>


<span class="hljs-comment"># Routes related to Products Page</span>


<span class="hljs-comment"># Routes related to Blog Page</span>


<span class="hljs-comment"># Routes related to Admin Page</span>

<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:
    app.run(debug=<span class="hljs-literal">True</span>)
</code></pre>
<p>Doesn't that look messy (imagining that you've built a large-scale app)? You have all your models and different routes inside the same file spread around here and there.</p>
<h2 id="heading-how-does-blueprints-solve-the-problem">How Does Blueprints Solve the Problem?</h2>
<p>Now, this is where Flask Blueprints come into picture. Blueprints help you structure your application by organizing the logic into subdirectories. In addition to that, you can store your templates and static files along with the logic in the same subdirectory.</p>
<p>So, with Blueprints now your same application will look like this:</p>
<pre><code class="lang-md">/blueprint-tutorial
├── /myapp<span class="hljs-emphasis">_with_</span>blueprints
│   ├── <span class="hljs-strong">__init__</span>.py
│   ├── /admin
│   │   ├── /templates
│   │   ├── /static
│   │   └── routes.py
│   ├── /core
│   │   ├── /templates
│   │   ├── /static
│   │   └── routes.py
│   ├── /products
│   │   ├── /templates
│   │   ├── /static
│   │   └── routes.py
│   └── /profile
|       ├── /templates
|       ├── /static
|       └── routes.py        
├── app.py
├── /static
└── /templates
</code></pre>
<p>Now you can see that you have clear separation of concerns. The logic related to admin resides inside the <code>admin</code> folder, the logic related to products resides inside the <code>products</code> folder and so on. </p>
<p>Additionally, we also separated the templates and static files in the subdirectories where they are required, so that irrelevant files don't load when going to a page that doesn't require them.</p>
<h2 id="heading-how-to-use-blueprints">How to Use Blueprints</h2>
<p>Now that you understand what problems Blueprints solves, let's see how we can use Blueprints in our applications.</p>
<h3 id="heading-how-to-define-a-blueprint">How to Define a Blueprint</h3>
<p>Let's define our very first blueprint for the <strong>admin</strong> functionality inside the <code>admin/routes.py</code> file:</p>
<pre><code class="lang-py"><span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> Blueprint


<span class="hljs-comment"># Defining a blueprint</span>
admin_bp = Blueprint(
    <span class="hljs-string">'admin_bp'</span>, __name__,
    template_folder=<span class="hljs-string">'templates'</span>,
    static_folder=<span class="hljs-string">'static'</span>
)
</code></pre>
<p>Since Blueprint is a Flask built-in concept, you can import it from the Flask library. While creating the object of the <code>Blueprint</code> class, the first parameter is the name you want to give to your Blueprint. This name will later be used for internal routing (we'll see below). </p>
<p>The second parameter is the name of the Blueprint package, generally <code>__name__</code>. This helps locate the <code>root_path</code> for the blueprint. </p>
<p>The third and fourth parameters passed are optional <a target="_blank" href="https://ashutoshkrris.hashnode.dev/what-are-args-and-kwargs-in-python">keyword arguments</a>. By defining the <code>template_folder</code> and <code>static_folder</code> parameters, you specify that you'll be using blueprint-specific templates and static files. </p>
<h3 id="heading-how-to-define-routes-with-blueprints">How to Define Routes with Blueprints</h3>
<p>Now that you have created a blueprint for the admin related functionality, you can use it while creating routes for the admins.</p>
<pre><code class="lang-py"><span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> Blueprint


<span class="hljs-comment"># Defining a blueprint</span>
admin_bp = Blueprint(
    <span class="hljs-string">'admin_bp'</span>, __name__,
    template_folder=<span class="hljs-string">'templates'</span>,
    static_folder=<span class="hljs-string">'static'</span>
)

<span class="hljs-meta">@admin_bp.route('/admin')   # Focus here</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">admin_home</span>():</span>
    <span class="hljs-keyword">return</span> <span class="hljs-string">"Hello Admin!"</span>
</code></pre>
<p>In the above snippet, focus on the line where the route is defined. Instead of the usual <code>@app.route('...')</code>, we have used <code>@admin_bp.route('...')</code>. This is how you bind a route to a particular blueprint.</p>
<h3 id="heading-how-to-register-your-blueprints">How to Register Your Blueprints</h3>
<p>Now you have a blueprint and a route registered to it. But, will your app automatically know about this blueprint? </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/Screenshot-2022-08-30-112849.png" alt="Image" width="600" height="400" loading="lazy">
<em>No. You do it.</em></p>
<p>So, let's do it. In the <code>__init__.py</code> file, we will create a Flask app and register our blueprints there:</p>
<pre><code class="lang-py"><span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> Flask


app = Flask(__name__)

<span class="hljs-keyword">from</span> .admin <span class="hljs-keyword">import</span> routes

<span class="hljs-comment"># Registering blueprints</span>
app.register_blueprint(admin.admin_bp)
</code></pre>
<p>To register the blueprint, we use the <code>register_blueprint()</code> method and pass the name of the blueprint. Additionally, you can pass other parameters to the method for more customization. One such is <code>url_prefix</code> that you may require.</p>
<pre><code class="lang-py">app.register_blueprint(admin.admin_bp, url_prefix=<span class="hljs-string">'/admin'</span>)
</code></pre>
<p>Similarly, you can register rest of your blueprints if you have more.</p>
<h2 id="heading-template-routing-with-blueprints">Template Routing with Blueprints</h2>
<p>Without Blueprints, in order to create links in your templates, you would use something similar to the below:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"{{ url_for('admin_home') }}"</span>&gt;</span>My Link<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
</code></pre>
<p>But with blueprints in place, now you can define your links as:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"{{ url_for('admin_bp.admin_home') }}"</span>&gt;</span>My Link<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
</code></pre>
<p>The <code>admin_bp</code> that we used above is the name we gave to our blueprint for internal routing while creating the object. </p>
<p>To print the blueprint name of the Jinja2 template that the current page belongs to, you can use <code>{{request.blueprint}}</code>.</p>
<p>Note: To use Blueprint-specific assets, you can use the <a href="https://flask-assets.readthedocs.io/en/latest/">Flask-Assets</a> library.</p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>Blueprint is an amazing tool to organize and structure your Flask applications. </p>
<p>In this article, you've learned what blueprints have to offer and how to use them in your Flask applications.</p>
<p>Thanks for reading!</p>
<p>You can follow me on <a target="_blank" href="https://twitter.com/ashutoshkrris">Twitter</a><a target="_blank" href="https://ireadblog.com/">.</a></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Python Tutorial – How to Create a URL Shortener using Flask ]]>
                </title>
                <description>
                    <![CDATA[ In this tutorial, we will build a URL shortener using Flask. This tool takes any URL and generates a shorter, more readable version like bit.ly.  The application will allow users to enter a URL and an optional custom short id and generate a shorter v... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/python-tutorial-how-to-create-a-url-shortener-using-flask/</link>
                <guid isPermaLink="false">66ba0ebb7282cc17abcf0c55</guid>
                
                    <category>
                        <![CDATA[ Flask Framework ]]>
                    </category>
                
                    <category>
                        <![CDATA[ projects ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ashutosh Krishna ]]>
                </dc:creator>
                <pubDate>Mon, 03 Jan 2022 18:26:36 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/12/URL-Shortener.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In this tutorial, we will build a URL shortener using Flask. This tool takes any URL and generates a shorter, more readable version like <a target="_blank" href="https://bitly.com/">bit.ly</a>. </p>
<p>The application will allow users to enter a URL and an optional custom short id and generate a shorter version.</p>
<p>Here's what we're going to build:</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/g6chXThUReU" 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>The frontend of the application is not attractive, because the main focus of the project is building a backend project. </p>
<p>Some sample shortened URLs are <a target="_blank" href="https://shorty-flask.herokuapp.com/mzkpK8sw">https://shorty-flask.herokuapp.com/mzkpK8sw</a> and <a target="_blank" href="https://shorty-flask.herokuapp.com/linkify">https://shorty-flask.herokuapp.com/linkify</a>.</p>
<h2 id="heading-create-the-virtual-environment-and-install-the-dependencies">Create the Virtual Environment and Install the Dependencies</h2>
<p>In this tutorial, we're going to use Pipenv to manage our virtual environment.</p>
<p><a target="_blank" href="https://pypi.org/project/pipenv/">Pipenv</a> is a tool that automatically creates and manages a virtualenv for your projects, as well as adds/removes packages from your <code>Pipfile</code> as you install/uninstall packages. It also generates the ever-important <code>Pipfile.lock</code>, which is used to produce deterministic builds. </p>
<p>You can read <a target="_blank" href="https://medium.com/analytics-vidhya/why-pipenv-over-venv-for-python-projects-a51fb6e4f31e">this article</a> to learn more about it.</p>
<p>Pipenv is an external library and we need to install it explicitly. To install the library, use the pip command:</p>
<pre><code class="lang-bash">pip install pipenv
</code></pre>
<p>Once it's installed, we can create a virtual environment and activate it using this command:</p>
<pre><code class="lang-bash">pipenv shell
</code></pre>
<p>To deactivate the virtual environment, we have a simple command:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">exit</span>
</code></pre>
<p>Once you have created and activated the virtual environment, you're ready to install the required libraries.</p>
<ul>
<li><p><a target="_blank" href="https://flask.palletsprojects.com/en/2.0.x/">Flask</a> is a simple, easy-to-use microframework for Python that can help build scalable and secure web applications. The module doesn't come pre-installed with Python, so we need to install it using the command:</p>
<pre><code class="lang-bash">  pipenv install Flask
</code></pre>
</li>
<li><p><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. To install the module, use the command:</p>
<pre><code class="lang-bash">  pipenv install Flask-Migrate
</code></pre>
</li>
<li><p><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. To install the module, use the command:</p>
<pre><code class="lang-bash">  pipenv install Flask-SQLAlchemy
</code></pre>
</li>
<li><p><a target="_blank" href="https://pypi.org/project/psycopg2/">Psycopg2</a> is the most popular PostgreSQL database adapter for the Python programming language. To install the module, use the command:</p>
<pre><code class="lang-bash">  pipenv install psycopg2
</code></pre>
</li>
<li><p><a target="_blank" href="https://gunicorn.org/">Gunicorn</a> is a Python WSGI HTTP Server for UNIX. To install the module, use the command:</p>
<pre><code class="lang-bash">  pipenv install gunicorn
</code></pre>
</li>
<li><p><a target="_blank" href="https://pypi.org/project/python-decouple/">Python Decouple</a>: We'll also use <a target="_blank" href="https://iread.ga/posts/49/do-you-really-need-environment-variables-in-python">environment variables</a> in this project. So, we are going to install another module called python-decouple to handle this:</p>
<pre><code class="lang-bash">  pipenv install python-decouple
</code></pre>
</li>
</ul>
<h2 id="heading-how-to-set-up-the-flask-project">How to Set Up the Flask Project</h2>
<p>The first thing we're going to do is to create a Flask project. If you check the <a target="_blank" href="https://flask.palletsprojects.com/en/2.0.x/quickstart/">official documentation</a> of Flask, you'll find a <a target="_blank" href="https://flask.palletsprojects.com/en/2.0.x/quickstart/#a-minimal-application">minimal application</a> there.</p>
<p>But, we're not going to follow that. We are going to write an application that is more extensible and has a good base structure. If you wish, you can follow <a target="_blank" href="https://iread.ga/posts/54/getting-started-with-flask">this guide</a> to get started with Flask.</p>
<p>Our application will exist within a package called <strong>core</strong>. To convert a usual directory to a Python package, we just need to include an <code>__init__.py</code> file. So, let's create our core package first.</p>
<pre><code class="lang-bash">$ mkdir core
</code></pre>
<p>After that, let's create the <code>__init__.py</code> file inside the core directory:</p>
<pre><code class="lang-bash">$ <span class="hljs-built_in">cd</span> core
$ touch __init__.py
$ <span class="hljs-built_in">cd</span> ..
</code></pre>
<p>In the root directory of the project, 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>


<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>


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">StagingConfig</span>(<span class="hljs-params">Config</span>):</span>
    DEVELOPMENT = <span class="hljs-literal">True</span>
    DEBUG = <span class="hljs-literal">True</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>


<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>
</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 <strong>SECRET_KEY</strong> and <strong>DATABASE_URL</strong>. Create a file named <code>.env</code> in the root directory and add the following content there:</p>
<pre><code>SECRET_KEY=verysecretkey
DATABASE_URL=sqlite:<span class="hljs-comment">///shorty.db</span>
APP_SETTINGS=config.DevelopmentConfig
FLASK_APP=core
</code></pre><p>Apart from the <strong>SECRET_KEY</strong> and <strong>DATABASE_URL</strong>, we've also specified <strong>APP_SETTINGS</strong> and <strong>FLASK_APP</strong>. </p>
<p>The <strong>APP_SETTINGS</strong> 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. The value of <strong>FLASK_APP</strong> is the name of the package we have created.</p>
<p>Now, we can add the following content in the <code>core/__init__.py</code> file:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> Flask
<span class="hljs-keyword">from</span> flask_sqlalchemy <span class="hljs-keyword">import</span> SQLAlchemy
<span class="hljs-keyword">from</span> flask_migrate <span class="hljs-keyword">import</span> Migrate
<span class="hljs-keyword">from</span> decouple <span class="hljs-keyword">import</span> config

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

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

<span class="hljs-keyword">from</span> core <span class="hljs-keyword">import</span> routes
</code></pre>
<p>In the above Python script, we are first importing the Flask class from the Flask module that we have installed. Next, we're creating an object <code>app</code> of class Flask. 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.</p>
<p>Next we are setting the app configurations to the <strong>APP_SETTINGS</strong> according to the variable in the <code>.env</code> file. To use Flask-SQLAlchemy and Flask-Migrate in our application, we just need to create objects of the <code>SQLAlchemy</code> class and <code>Migrate</code> class from the <code>flask_sqlalchemy</code> and <code>flask_migrate</code> libraries respectively.</p>
<p>The application then imports the <code>routes</code> module, which doesn't exist yet.</p>
<p>To run the application, we'll use a <code>main.py</code> file with the following content:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> core <span class="hljs-keyword">import</span> app

<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:
    app.run()
</code></pre>
<h2 id="heading-how-to-create-the-database-table">How to Create the Database Table</h2>
<p>To define our database tables, we’ll create a <code>models.py</code> file within the core package. Inside that, we can write the following code :</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> core <span class="hljs-keyword">import</span> db
<span class="hljs-keyword">from</span> datetime <span class="hljs-keyword">import</span> datetime

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ShortUrls</span>(<span class="hljs-params">db.Model</span>):</span>
    id = db.Column(db.Integer, primary_key=<span class="hljs-literal">True</span>)
    original_url = db.Column(db.String(<span class="hljs-number">500</span>), nullable=<span class="hljs-literal">False</span>)
    short_id = db.Column(db.String(<span class="hljs-number">20</span>), nullable=<span class="hljs-literal">False</span>, unique=<span class="hljs-literal">True</span>)
    created_at = db.Column(db.DateTime(), default=datetime.now(), nullable=<span class="hljs-literal">False</span>)
</code></pre>
<p>We first imported the <code>db</code> object that we had initialized in the <code>__init__.py</code> file. Then we created a <code>ShortUrls</code> class with a few fields such as <strong>id</strong> (primary key), <strong>original_url</strong> (provided by the user), <strong>short_id</strong> (generated by us or provided by the user), and <strong>created_at</strong> (timestamp).</p>
<p>We can then use <strong>Flask-Migrate</strong> commands to migrate the database with the new tables. The commands we'll use are:</p>
<ul>
<li><code>flask db init</code> — to initialize the database at the beginning (to be used only once)</li>
<li><code>flask db migrate</code> — to migrate the new changes to the database (to be used every time we make changes in the database tables)</li>
<li><code>flask db upgrade</code> — to upgrade our database with the new changes (to be used with the migrate command)</li>
</ul>
<p>After we run the database initialization we will see a new folder called “<strong>migrations</strong>” in the project. This holds the setup necessary for Alembic to run migrations against the project. </p>
<p>Inside of “migrations”, we will see that it has a folder called “versions”, which will contain the migration scripts as they are created.</p>
<h1 id="heading-how-to-create-the-homepage-for-shortening-urls"><strong>How to Create the Homepage for Shortening URLs</strong></h1>
<p>In this step, we will create a Flask route for the index page, which will allow users to enter a URL that we then save into the database. This route will use the custom short id provided by the user or generate one on its own, construct the short URL, and then render it as a result.</p>
<p>First, let’s create a <code>routes.py</code> file in the core package and create a Python function to generate short id.</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> random <span class="hljs-keyword">import</span> choice
<span class="hljs-keyword">import</span> string

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">generate_short_id</span>(<span class="hljs-params">num_of_chars: int</span>):</span>
    <span class="hljs-string">"""Function to generate short_id of specified number of characters"""</span>
    <span class="hljs-keyword">return</span> <span class="hljs-string">''</span>.join(choice(string.ascii_letters+string.digits) <span class="hljs-keyword">for</span> _ <span class="hljs-keyword">in</span> range(num_of_chars))
</code></pre>
<p>In order to generate a short id, we have used the <strong>choice</strong> method from Python’s <strong>random</strong> module. Also, we have used Python’s in-built <strong>string</strong> module for letters (lowercase + uppercase), and digits.</p>
<p>Now, we need to create a template for the index page that will be served by the index route. This template will have a simple form where a user can input the original URL and custom short id (optional) and submit it. </p>
<p>But we’ll not create <code>index.html</code> directly. We can use the Template Inheritance concept in Jinja2. So, let's create a <strong>templates</strong> directory within the <code>core</code> package and create a <code>base.html</code> file inside that. You can paste the HTML code into that file.</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-comment">&lt;!-- Required meta tags --&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">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, shrink-to-fit=no"</span>&gt;</span>

    <span class="hljs-comment">&lt;!-- Bootstrap CSS --&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.1.0/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-KyZXEAg3QhqLMpG8r+8fhAXLRk2vvoC2f3B09zVXn8CA5QIVfZOJ3BCsw2P0p/We"</span> <span class="hljs-attr">crossorigin</span>=<span class="hljs-string">"anonymous"</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>{% block title %} {% endblock %}<span class="hljs-tag">&lt;/<span class="hljs-name">title</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">body</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 mt-3"</span>&gt;</span>
        {% for message in get_flashed_messages() %}
            <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>&gt;</span>{{ message }}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        {% endfor %}
        {% block content %} {% endblock %}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

    <span class="hljs-comment">&lt;!-- Optional JavaScript --&gt;</span>
    <span class="hljs-comment">&lt;!-- jQuery first, then Popper.js, then Bootstrap JS --&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.3.1.slim.min.js"</span> <span class="hljs-attr">integrity</span>=<span class="hljs-string">"sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo"</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/@popperjs/core@2.9.3/dist/umd/popper.min.js"</span> <span class="hljs-attr">integrity</span>=<span class="hljs-string">"sha384-eMNCOe7tC1doHpGoWe/6oMVemdAVTMs2xqW4mwXrXsW0L84Iytr2wi5v2QjrP/xp"</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.1.0/dist/js/bootstrap.min.js"</span> <span class="hljs-attr">integrity</span>=<span class="hljs-string">"sha384-cn7l7gDp0eyniUwwAZgrzD06kc/tftFf19TOAs2zVinnD/C7E91j9yyk5//jjpt/"</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">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>Note that, for styling, we’re using <a target="_blank" href="https://getbootstrap.com/">Bootstrap</a> here.</p>
<p>Most of the code in the preceding block is standard HTML code required for Bootstrap. The <code>&lt;meta&gt;</code> tags provide information for the web browser, the <code>&lt;link&gt;</code> tag links the Bootstrap CSS files, and the <code>&lt;script&gt;</code> tags are links to JavaScript code that allows some additional Bootstrap features. </p>
<p>You can check out the <a target="_blank" href="https://getbootstrap.com/">Bootstrap documentation</a> for more information.</p>
<p>The <code>&lt;title&gt;{% block title %} {% endblock %}&lt;/title&gt;</code> tag allows the inheriting templates to define a custom title. </p>
<p>We use the <code>for message in get_flashed_messages()</code> loop to display the flashed messages (warnings, alerts, and so on). </p>
<p>The <code>{% block content %} {% endblock %}</code> placeholder is where inheriting templates place the content so that all templates have access to this base template, which avoids repetition.</p>
<p>Next, create the <code>index.html</code> file that will extend this <code>base.html</code> file:</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 mb-3"</span>&gt;</span>{% block title %} Welcome to Shorty {% endblock %}<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">"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-2"</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-8"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">method</span>=<span class="hljs-string">"post"</span> <span class="hljs-attr">action</span>=<span class="hljs-string">"{{url_for('index')}}"</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 mb-3"</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">name</span>=<span class="hljs-string">"url"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"url"</span>
                    <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Enter looooooooooooong URL"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-control"</span>
                    <span class="hljs-attr">value</span>=<span class="hljs-string">"{{ request.form['url'] }}"</span> <span class="hljs-attr">autofocus</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">input</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"url"</span>&gt;</span>URL<span class="hljs-tag">&lt;/<span class="hljs-name">label</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-floating mb-3"</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">name</span>=<span class="hljs-string">"custom_id"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"custom_id"</span>
                    <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Want to customise? (optional)"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-control"</span>
                    <span class="hljs-attr">value</span>=<span class="hljs-string">"{{ request.form['custom_id'] }}"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">input</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"custom_id"</span>&gt;</span>Custom Short ID<span class="hljs-tag">&lt;/<span class="hljs-name">label</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 text-center"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-lg btn-primary"</span>&gt;</span>Shorten<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">form</span>&gt;</span>

            {% if short_url %}
            <span class="hljs-tag">&lt;<span class="hljs-name">hr</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">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"{{ short_url }}"</span> <span class="hljs-attr">target</span>=<span class="hljs-string">"_blank"</span>&gt;</span>{{ short_url }}<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</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> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-md-2"</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>Here we extend <code>base.html</code>, define a title, and create a form with two inputs named <code>url</code> and <code>custom_id</code>. </p>
<p>The <code>url</code> input will allow users to enter URLs to shorten. It has a value of <code>request.form['url']</code>, which stores data in cases of submission failure (that is if the user provides no URL). Similarly, <code>custom_id</code> input will allow users to enter a custom short id. We then have a submit button.</p>
<p>Then we check if the <code>short_url</code> variable has any value—this is true if the form submits and the short URL generates successfully. If the condition is true, we display the short URL under the form.</p>
<p>Now we can rewrite our index view function in <code>routes.py</code> as:</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> core.models <span class="hljs-keyword">import</span> ShortUrls
<span class="hljs-keyword">from</span> core <span class="hljs-keyword">import</span> app, db
<span class="hljs-keyword">from</span> random <span class="hljs-keyword">import</span> choice
<span class="hljs-keyword">import</span> string
<span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> render_template, request, flash, redirect, url_for


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">generate_short_id</span>(<span class="hljs-params">num_of_chars: int</span>):</span>
    <span class="hljs-string">"""Function to generate short_id of specified number of characters"""</span>
    <span class="hljs-keyword">return</span> <span class="hljs-string">''</span>.join(choice(string.ascii_letters+string.digits) <span class="hljs-keyword">for</span> _ <span class="hljs-keyword">in</span> range(num_of_chars))


<span class="hljs-meta">@app.route('/', methods=['GET', 'POST'])</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">index</span>():</span>
    <span class="hljs-keyword">if</span> request.method == <span class="hljs-string">'POST'</span>:
        url = request.form[<span class="hljs-string">'url'</span>]
        short_id = request.form[<span class="hljs-string">'custom_id'</span>]

        <span class="hljs-keyword">if</span> short_id <span class="hljs-keyword">and</span> ShortUrls.query.filter_by(short_id=short_id).first() <span class="hljs-keyword">is</span> <span class="hljs-keyword">not</span> <span class="hljs-literal">None</span>:
            flash(<span class="hljs-string">'Please enter different custom id!'</span>)
            <span class="hljs-keyword">return</span> redirect(url_for(<span class="hljs-string">'index'</span>))

        <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> url:
            flash(<span class="hljs-string">'The URL is required!'</span>)
            <span class="hljs-keyword">return</span> redirect(url_for(<span class="hljs-string">'index'</span>))

        <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> short_id:
            short_id = generate_short_id(<span class="hljs-number">8</span>)

        new_link = ShortUrls(
            original_url=url, short_id=short_id, created_at=datetime.now())
        db.session.add(new_link)
        db.session.commit()
        short_url = request.host_url + short_id

        <span class="hljs-keyword">return</span> render_template(<span class="hljs-string">'index.html'</span>, short_url=short_url)

    <span class="hljs-keyword">return</span> render_template(<span class="hljs-string">'index.html'</span>)
</code></pre>
<p>The <code>index()</code> function is a Flask <strong>view function</strong>, which is a function decorated using the special <code>@app.route</code> <a target="_blank" href="https://en.wikipedia.org/wiki/Python_syntax_and_semantics#Decorators">decorator</a>. Its return value gets converted into an HTTP response that an HTTP client, such as a web browser, displays.</p>
<p>Inside the <code>index()</code> view function, we accept both GET and POST requests by passing <code>methods=['GET', 'POST']</code> to the <code>app.route()</code> decorator.</p>
<p>Then if the request is a GET request, it skips the <code>if request.method == 'POST'</code> condition until the last line. This is where we render a template called <code>index.html</code>, which will contain a form for users to enter a URL to shorten.</p>
<p>If the request is a POST request, the <code>if request.method == 'POST'</code> condition is true, which means a user has submitted a URL. We store the URL in the <code>url</code> variable. If the user has submitted an empty form, you flash the message <code>The URL is required!</code> and redirect to the index page. </p>
<p>If the user has entered <code>custom_id</code>, we store it in <strong>short_id</strong>, else we generate random short id using the function that we had created before.</p>
<p>If the user has submitted a URL, we create a <code>new_link</code> with all the data such as <code>original_url</code> <code>short_id</code> and <code>created_at</code>. Then we commit the transaction.</p>
<p>We then construct the short URL using <code>request.host_url</code>, which is an attribute that Flask’s <code>request</code> object provides to access the URL of the application’s host. This will be <code>http://127.0.0.1:5000/</code> in a development environment and <code>our_domain</code> if we deploy our application. </p>
<p>For example, the <code>short_url</code> variable will have a value like <code>http://127.0.0.1:5000/asdf1gHJ</code>, which is the short URL that will redirect users to the original URL stored in the database with the ID that matches the <code>asdf1gHJ</code>.</p>
<p>Lastly, we render the <code>index.html</code> template passing the <code>short_url</code> variable to it.</p>
<p>We can now run the server and test our view function.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/12/1_ufNnbLzmSkxovhLYbJybHA.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>We have created a Flask application with a page that accepts URLs and generates shorter ones, but the URLs don’t do anything yet. </p>
<p>In the next step, we’ll add a route that extracts the short_id from the short URL, finds the original URL, and redirects users to it.</p>
<h2 id="heading-how-to-add-the-redirect-route">How to Add the Redirect Route</h2>
<p>In this step, we will add a new route that takes the short id the application generates and fetches the original URL. Finally, we will redirect users to the original URL.</p>
<pre><code class="lang-python"><span class="hljs-meta">@app.route('/&lt;short_id&gt;')</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">redirect_url</span>(<span class="hljs-params">short_id</span>):</span>
    link = ShortUrls.query.filter_by(short_id=short_id).first()
    <span class="hljs-keyword">if</span> link:
        <span class="hljs-keyword">return</span> redirect(link.original_url)
    <span class="hljs-keyword">else</span>:
        flash(<span class="hljs-string">'Invalid URL'</span>)
        <span class="hljs-keyword">return</span> redirect(url_for(<span class="hljs-string">'index'</span>))
</code></pre>
<p>This new route accepts a value <code>short_id</code> through the URL and passes it to the <code>url_redirect()</code> view function. For example, visiting <code>[http://127.0.0.1:5000/asdf1gHJ](http://127.0.0.1:5000/asdf1gHJ)</code> would pass the string <code>'asdf1gHJ'</code> to the <code>short_id</code> parameter.</p>
<p>Inside the view function, we fetch the link from the database using the <code>short_id</code>. If it is not None, the view function will redirect the user to the <code>original_url</code> associated with this <code>short_id</code> using the <code>redirect()</code> Flask helper function. Otherwise, it will flash an error message to inform the user that the URL is invalid and redirect them to the index page.</p>
<p>Now we can again run the server and finally test the application.</p>
<h2 id="heading-how-to-deploy-the-application-on-heroku">How to Deploy the Application on Heroku</h2>
<p>To deploy our app on <a target="_blank" href="https://heroku.com/">Heroku</a>, we need to make a few changes to our project. But first, you should create a free account on Heroku. </p>
<p>Head over to <a target="_blank" href="https://signup.heroku.com/">heroku.com</a> and create an account. Once you have created the account, you're ready to proceed.</p>
<p>Login to your Heroku account, and you'll be welcomed with a similar screen to this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/12/Screenshot-2021-12-26-130519.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Click on the <strong>New</strong> button and then click on <strong>Create new app</strong>. Enter the app name and then click on the <strong>Create app button</strong>. Make sure the name is available.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/12/Screenshot-2021-12-26-130553.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Click on the <strong>Settings</strong> tab, and scroll down to <strong>Buildpacks</strong>. Click on the <strong>Add buildpack</strong> button and add <strong>Python</strong>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/12/Screenshot-2021-12-26-130636.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Since we'll require a database for this application, we are going to add a Postgres database (available for free on Heroku) in the resources. </p>
<p>Click on the <strong>Resources</strong> tab and search for Postgres in the search box. Select <strong>Heroku Postgres</strong> in the search results, and then click on <strong>Submit order form</strong> to add it to the resources.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/12/Screenshot-2021-12-26-131308.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>As we've used environment variables in our project, we need to add them on Heroku. </p>
<p>Click on the <strong>Settings</strong> tab and scroll to <strong>Config Vars</strong> and click on <strong>Reveal Config Vars</strong>. Open your <code>.env</code> file in the project and copy and paste it into your Config Vars as below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/12/Screenshot-2021-12-26-131347.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Notice that, we have set the <code>APP_SETTINGS</code> to <code>config.ProductionConfig</code> because we're deploying the application publicly. </p>
<p>We'll be deploying our application using GitHub, which will make our task easier. If you don't have a GitHub account, create one for yourself <a target="_blank" href="https://github.com/signup?ref_cta=Sign+up&amp;ref_loc=header+logged+out&amp;ref_page=%2F&amp;source=header-home">here</a>. If you have a GitHub account, log in to your account. Once you login, you'll see a similar screen:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/12/screenshot-2021-12-02-095432_kwefk5.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Create a repository for your project using the green <strong>New</strong> button. Then go to your project on your system. Make sure you have Git installed in your system. If not, install it from <a target="_blank" href="https://git-scm.com/downloads">here</a>. Open a terminal in your project and write the below commands:</p>
<pre><code class="lang-bash">$ git init
$ git remote add origin &lt;your-repository-url-here&gt;
$ git add .
$ git commit -m <span class="hljs-string">"Initial commit"</span>
$ git push origin main
</code></pre>
<p>Replace the <code>&lt;your-repository-url-here&gt;</code> with the URL provided by GitHub.</p>
<p>Now we need to add two new files required by Heroku – <code>Procfile</code> and <code>runtime.txt</code>:</p>
<pre><code class="lang-procfile">web: gunicorn main:app
</code></pre>
<p>This declares a single process type, <code>web</code>, and the command needed to run it. </p>
<p>The name <code>web</code> is important here. It declares that this process type will be attached to the <a target="_blank" href="https://devcenter.heroku.com/articles/http-routing">HTTP routing</a> stack of Heroku, and will receive web traffic when deployed. Notice that the Procfile file doesn't have any extension.</p>
<p>Next, create a <code>runtime.txt</code> file and add your Python version there as:</p>
<pre><code class="lang-markdown">python-3.9.7
</code></pre>
<p>Also, create a <code>.gitignore</code> file and add the following content:</p>
<pre><code class="lang-markdown"><span class="hljs-section"># Django #</span>
<span class="hljs-emphasis">*.log
*</span>.pot
<span class="hljs-emphasis">*.pyc
<span class="hljs-strong">__pycache__</span>
media
db.sqlite3

# Backup files # 
*</span>.bak 

<span class="hljs-section"># If you are using PyCharm # </span>
.idea/<span class="hljs-strong">**/workspace.xml 
.idea/**</span>/tasks.xml 
.idea/dictionaries 
.idea/<span class="hljs-strong">**/dataSources/ 
.idea/**</span>/dataSources.ids 
.idea/<span class="hljs-strong">**/dataSources.xml 
.idea/**</span>/dataSources.local.xml 
.idea/<span class="hljs-strong">**/sqlDataSources.xml 
.idea/**</span>/dynamic.xml 
.idea/<span class="hljs-strong">**/uiDesigner.xml 
.idea/**</span>/gradle.xml 
.idea/<span class="hljs-strong">**/libraries 
<span class="hljs-emphasis">*.iws /out/ 

# Python # 
*</span>.py[cod] 
<span class="hljs-emphasis">*$py.class 

# Distribution / packaging 
.Python build/ 
develop-eggs/ 
dist/ 
downloads/ 
eggs/ 
.eggs/ 
lib/ 
lib64/ 
parts/ 
sdist/ 
var/ 
wheels/ 
*</span>.egg-info/ 
.installed.cfg 
<span class="hljs-emphasis">*.egg 
*</span>.manifest 
<span class="hljs-emphasis">*.spec 

# Installer logs 
pip-log.txt 
pip-delete-this-directory.txt 

# Unit test / coverage reports 
htmlcov/ 
.tox/ 
.coverage 
.coverage.*</span> 
.cache 
.pytest<span class="hljs-emphasis">_cache/ 
nosetests.xml 
coverage.xml 
*.cover 
.hypothesis/ 

# Jupyter Notebook 
.ipynb_</span>checkpoints 

# pyenv 
.python-version 

# celery 
celerybeat-schedule.<span class="hljs-emphasis">* 

# SageMath parsed files 
*</span>.sage.py 

# Environments 
.env 
.venv 
env/ 
venv/ 
ENV/ 
env.bak/ 
venv.bak/ 

# mkdocs documentation 
/site 

# mypy 
.mypy<span class="hljs-emphasis">_cache/ 

# Sublime Text # 
*.tmlanguage.cache 
*.tmPreferences.cache 
*.stTheme.cache 
*.sublime-workspace 
*.sublime-project 

# sftp configuration file 
sftp-config.json 

# Package control specific files Package 
Control.last-run 
Control.ca-list 
Control.ca-bundle 
Control.system-ca-bundle 
GitHub.sublime-settings 

# Visual Studio Code # 
.vscode/* 
!.vscode/settings.json 
!.vscode/tasks.json 
!.vscode/launch.json 
!.vscode/extensions.json 
.history</span></span>
</code></pre>
<p>This tells Git to ignore these files.</p>
<p>Now, we have made enough changes and we are ready to commit and push it to the GitHub repository using the commands:</p>
<pre><code class="lang-bash">$ git add .
$ git commit -m <span class="hljs-string">"Ready for deployment"</span>
$ git push origin main
</code></pre>
<p>Now we're completely ready to deploy our app on Heroku. </p>
<p>Open the Heroku app and click on the <strong>Deploy</strong> tab. In the <strong>Deployment method</strong> on the page, choose GitHub. Search for your repository and click on Connect to select it.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/12/Screenshot-2021-12-26-131430.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Once it is connected successfully, you'll see a button called Deploy Branch. Click on the button and the deployment process will start:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/12/Screenshot-2021-12-26-131502.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Heroku will install all the dependencies mentioned in the requirements.txt file and will use the Python version mentioned in the runtime.txt file. After the process is completed, you will see a success message like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/12/Screenshot-2021-12-26-131709.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Our app has been deployed successfully!</p>
<p>But there's one step still left. If you remember, whenever we made any changes to the database, we needed to migrate the database. Similarly here also, we need to migrate the database. </p>
<p>Click on <strong>More</strong> and then on <strong>Run Console</strong> to run bash. Once you click on that, you'll find a text box. Write the below command there:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/12/Screenshot-2021-12-26-132156.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Once you run the command, you'll see the database migrations happening. With this, your app has been deployed successfully and you're ready to test it!</p>
<p>Now you can follow <a target="_blank" href="https://devcenter.heroku.com/articles/custom-domains">this tutorial</a> to add a custom domain to your Heroku app as the Heroku URL is way too long.</p>
<h1 id="heading-wrapping-up"><strong>Wrapping Up</strong></h1>
<p>We have created a Flask application that allows users to enter a long URL and generate a shorter version. If you want, you can add more features to this application such as User Authentication, Shortened URLs Statistics, and so on.</p>
<p>Thanks for reading!</p>
<p>Github repository: <a target="_blank" href="https://github.com/ashutoshkrris/Flask-URL-Shortener">https://github.com/ashutoshkrris/Flask-URL-Shortener</a></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Python Project – How to Create a Horoscope API with Beautiful Soup and Flask ]]>
                </title>
                <description>
                    <![CDATA[ Have you ever read your horoscope in the newspaper or seen it on television? Well, I'm not sure about other countries, but in my country of India, people still read their horoscopes.  And this is where I got the idea for this tutorial. It might sound... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/python-project-build-an-api-with-beautiful-soup-and-flask/</link>
                <guid isPermaLink="false">66ba0eb47282cc17abcf0c53</guid>
                
                    <category>
                        <![CDATA[ api ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Flask Framework ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                    <category>
                        <![CDATA[ web scraping ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ashutosh Krishna ]]>
                </dc:creator>
                <pubDate>Fri, 17 Dec 2021 18:29:53 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/12/horoscope-api-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Have you ever read your horoscope in the newspaper or seen it on television? Well, I'm not sure about other countries, but in my country of India, people still read their horoscopes. </p>
<p>And this is where I got the idea for this tutorial. It might sound a bit old-fashioned, but the main focus here is not on the horoscope itself – it's just the vehicle for our learning. </p>
<p>In this article, we're going to scrape a website called <a target="_blank" href="https://www.horoscope.com/us/index.aspx">Horoscope.com</a> using Beautiful Soup and then create our own API using Flask. This API, if deployed on a public server, can then be used by other developers who would wish to create a website to show their horoscope or an app for the same.</p>
<h2 id="heading-how-to-set-up-the-project">How to Set Up the Project</h2>
<p>First of all, we're going to create a virtual environment within which we'll install all the required dependencies. </p>
<p>Python now ships with the 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>To activate the virtual environment named <code>env</code>, use the command:</p>
<ul>
<li>On Windows:</li>
</ul>
<pre><code class="lang-terminal">env\Scripts\activate.bat
</code></pre>
<ul>
<li>On Linux and MacOS:</li>
</ul>
<pre><code class="lang-bash"><span class="hljs-built_in">source</span> env/bin/activate
</code></pre>
<p>To deactivate the environment (not required at this stage):</p>
<pre><code class="lang-bash">deactivate
</code></pre>
<p>Now we're ready to install the dependencies. The modules and libraries we are going to use in this project are:</p>
<ul>
    <li>requests:&nbsp;<a href="https://docs.python-requests.org/en/latest/">Requests</a>&nbsp;allow you to send HTTP/1.1 requests extremely easily. The module doesn't come pre-installed with Python, so we need to install it using the command:

    <pre><code class="language-bash">$ pip install requests</code></pre>
    </li>
    <li>bs4:&nbsp;<a href="http://www.crummy.com/software/BeautifulSoup/">Beautiful Soup</a>(bs4)&nbsp;is a Python library for pulling data out of HTML and XML files.&nbsp;The module doesn't come pre-installed with Python, so we need to install it using the command:
    <pre><code class="language-bash">$ pip install bs4</code></pre>
    </li>
    <li>Flask:&nbsp;<a href="https://flask.palletsprojects.com/">Flask</a> is a simple, easy-to-use microframework for Python that can help build scalable and secure web applications. The module doesn't come pre-installed with Python, so we need to install it using the command:
    <pre><code class="language-bash">$ pip install flask</code></pre>
    </li>
    <li>Flask-RESTX:&nbsp;<a href="https://flask-restx.readthedocs.io/en/latest/quickstart.html">Flask-RESTX</a> lets you create APIs with Swagger Documentation. The module doesn't come pre-installed with Python, so we need to install it using the command:
    <pre><code class="language-bash">$ pip install flask-restx</code></pre>
    </li>
</ul>

<p>We'll also use environment variables in this project. So, we are going to install another module called <strong>python-decouple</strong> to handle this:</p>
<pre><code class="lang-bash">pip install python-decouple
</code></pre>
<p>To learn more about environment variables in Python, you can check out <a target="_blank" href="https://iread.ga/posts/49/do-you-really-need-environment-variables-in-python">this article</a>.</p>
<h2 id="heading-project-workflow">Project Workflow</h2>
<p>The basic workflow of the project will be like this:</p>
<ol>
<li>The horoscope data will be scraped from <a target="_blank" href="https://www.horoscope.com/us/index.aspx">Horoscope.com</a>.</li>
<li>The data will then be used by our Flask server to send JSON response to the user.</li>
</ol>
<h2 id="heading-how-to-set-up-a-flask-project">How to Set Up a Flask Project</h2>
<p>The first thing we're going to do is to create a Flask project. If you check the <a target="_blank" href="https://flask.palletsprojects.com/en/2.0.x/quickstart/">official documentation</a> of Flask, you'll find a <a target="_blank" href="https://flask.palletsprojects.com/en/2.0.x/quickstart/#a-minimal-application">minimal application</a> there. </p>
<p>But, we're not going to follow that. We are going to write an application that is more extensible and has a good base structure. If you wish, you can follow <a target="_blank" href="https://iread.ga/posts/54/getting-started-with-flask">this guide</a> to get started with Flask.</p>
<p>Our application will exist within a package called <strong>core</strong>. To convert a usual directory to a Python package, we just need to include an <code>__init__.py</code> file. So, let's create our core package first.</p>
<pre><code class="lang-bash">$ mkdir core
</code></pre>
<p>After that, let's create the <code>__init__.py</code> file inside the core directory:</p>
<pre><code class="lang-bash">$ <span class="hljs-built_in">cd</span> core
$ touch __init__.py
$ <span class="hljs-built_in">cd</span> ..
</code></pre>
<p>In the root directory of the project, 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


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Config</span>(<span class="hljs-params">object</span>):</span>
    SECRET_KEY = config(<span class="hljs-string">'SECRET_KEY'</span>, default=<span class="hljs-string">'guess-me'</span>)
    DEBUG = <span class="hljs-literal">False</span>
    TESTING = <span class="hljs-literal">False</span>
    CSRF_ENABLED = <span class="hljs-literal">True</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>
    MAIL_DEBUG = <span class="hljs-literal">False</span>


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">StagingConfig</span>(<span class="hljs-params">Config</span>):</span>
    DEVELOPMENT = <span class="hljs-literal">True</span>
    DEBUG = <span class="hljs-literal">True</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>


<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>
</code></pre>
<p>In the above script, we have created a <em>Config</em> class and defined various attributes inside that. Also, we have created different child classes (as per different stages of development) that inherit the <em>Config</em> class.</p>
<p>Notice that we have the SECRET_KEY set to an environment variable named <strong>SECRET_KEY</strong>. Create a file named <code>.env</code> in the root directory and add the following content there:</p>
<pre><code class="lang-env">APP_SETTINGS=config.DevelopmentConfig
SECRET_KEY=gufldksfjsdf
</code></pre>
<p>Apart from <strong>SECRET_KEY</strong>, we have <strong>APP_SETTINGS</strong> that 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>Now, we can add the following content in the <code>__init__.py</code> file:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> Flask
<span class="hljs-keyword">from</span> decouple <span class="hljs-keyword">import</span> config
<span class="hljs-keyword">from</span> flask_restx <span class="hljs-keyword">import</span> Api

app = Flask(__name__)
app.config.from_object(config(<span class="hljs-string">"APP_SETTINGS"</span>))
api = Api(
    app,
    version=<span class="hljs-string">'1.0'</span>,
    title=<span class="hljs-string">'Horoscope API'</span>,
    description=<span class="hljs-string">'Get horoscope data easily using the below APIs'</span>,
    license=<span class="hljs-string">'MIT'</span>,
    contact=<span class="hljs-string">'Ashutosh Krishna'</span>,
    contact_url=<span class="hljs-string">'https://ashutoshkrris.tk'</span>,
    contact_email=<span class="hljs-string">'contact@ashutoshkrris.tk'</span>,
    doc=<span class="hljs-string">'/'</span>,
    prefix=<span class="hljs-string">'/api/v1'</span>
)
</code></pre>
<p>In the above Python script, we are first importing the Flask class from the Flask module that we have installed. Next, we're creating an object <code>app</code> of class Flask. 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. </p>
<p>Next we are setting the app configurations to the <strong>APP_SETTINGS</strong> according to the variable in the <code>.env</code> file. </p>
<p>Apart from that, we have created an object of the <em>Api</em> class. We need to pass various arguments to it. We can find the Swagger documentation on the <code>/</code> route. The <code>/api/v1</code> will be prefixed on each API route. </p>
<p>For now, let's create a <code>routes.py</code> file in the <code>core</code> package and just add the following namespace:</p>
<pre><code class="lang-py"><span class="hljs-keyword">from</span> core <span class="hljs-keyword">import</span> api
<span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> jsonify

ns = api.namespace(<span class="hljs-string">'/'</span>, description=<span class="hljs-string">'Horoscope APIs'</span>)
</code></pre>
<p>We need to import the routes in the <code>__init__.py</code> file:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> Flask
<span class="hljs-keyword">from</span> decouple <span class="hljs-keyword">import</span> config
<span class="hljs-keyword">from</span> flask_restx <span class="hljs-keyword">import</span> Api

app = Flask(__name__)
app.config.from_object(config(<span class="hljs-string">"APP_SETTINGS"</span>))
api = Api(
    app,
    version=<span class="hljs-string">'1.0'</span>,
    title=<span class="hljs-string">'Horoscope API'</span>,
    description=<span class="hljs-string">'Get horoscope data easily using the below APIs'</span>,
    license=<span class="hljs-string">'MIT'</span>,
    contact=<span class="hljs-string">'Ashutosh Krishna'</span>,
    contact_url=<span class="hljs-string">'https://ashutoshkrris.tk'</span>,
    contact_email=<span class="hljs-string">'contact@ashutoshkrris.tk'</span>,
    doc=<span class="hljs-string">'/'</span>,
    prefix=<span class="hljs-string">'/api/v1'</span>
)

<span class="hljs-keyword">from</span> core <span class="hljs-keyword">import</span> routes            <span class="hljs-comment"># Add this line</span>
</code></pre>
<p>We're now just left with one file which will help us run the Flask server:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> core <span class="hljs-keyword">import</span> app

<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:
    app.run()
</code></pre>
<p>Once you run this file using the <code>python main.py</code> command, you'll see a similar output:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/12/Screenshot-2021-12-16-160820.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Now, we are ready to scrape the data from the Horoscope website.</p>
<h2 id="heading-how-to-scrape-the-data-from-horoscopecom">How to Scrape the Data from Horoscope.com</h2>
<p>If you open <a target="_blank" href="https://www.horoscope.com/us/horoscopes/general/horoscope-general-daily-today.aspx">Horoscope.com</a> and choose your zodiac sign, the horoscope data for your zodiac sign for today will be shown.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/12/Screenshot-2021-12-16-073450.png" alt="Image" width="600" height="400" loading="lazy">
<em>Source: Horoscope.com</em></p>
<p>In the above image, you can see you can view the horoscope for yesterday, tomorrow, weekly, monthly or even a custom date. We're going to use all of these.</p>
<p>But first if you see the URL of the current page, it is something like: <a target="_blank" href="https://www.horoscope.com/us/horoscopes/general/horoscope-general-daily-today.aspx?sign=10">https://www.horoscope.com/us/horoscopes/general/horoscope-general-daily-today.aspx?sign=10</a> . </p>
<p>The URL has two variables, if you see clearly, <strong>sign</strong> and <strong>today</strong>. The value of variable <strong>sign</strong> will be assigned according to the zodiac sign. The variable <strong>today</strong> can be replaced with <strong>yesterday</strong> and <strong>tomorrow</strong>.</p>
<p>The dictionary below can help us with the zodiac signs:</p>
<pre><code class="lang-python">ZODIAC_SIGNS = {
    <span class="hljs-string">"Aries"</span>: <span class="hljs-number">1</span>,
    <span class="hljs-string">"Taurus"</span>: <span class="hljs-number">2</span>,
    <span class="hljs-string">"Gemini"</span>: <span class="hljs-number">3</span>,
    <span class="hljs-string">"Cancer"</span>: <span class="hljs-number">4</span>,
    <span class="hljs-string">"Leo"</span>: <span class="hljs-number">5</span>,
    <span class="hljs-string">"Virgo"</span>: <span class="hljs-number">6</span>,
    <span class="hljs-string">"Libra"</span>: <span class="hljs-number">7</span>,
    <span class="hljs-string">"Scorpio"</span>: <span class="hljs-number">8</span>,
    <span class="hljs-string">"Sagittarius"</span>: <span class="hljs-number">9</span>,
    <span class="hljs-string">"Capricorn"</span>: <span class="hljs-number">10</span>,
    <span class="hljs-string">"Aquarius"</span>: <span class="hljs-number">11</span>,
    <span class="hljs-string">"Pisces"</span>: <span class="hljs-number">12</span>
}
</code></pre>
<p>This means that if your zodiac sign is <strong>Capricorn</strong>, the value of <strong>sign</strong> in the URL will be <strong>10</strong>. </p>
<p>Next, if we wish to get the horoscope data for a custom date, the URL <a target="_blank" href="https://www.horoscope.com/us/horoscopes/general/horoscope-archive.aspx?sign=10&amp;laDate=20211213">https://www.horoscope.com/us/horoscopes/general/horoscope-archive.aspx?sign=10&amp;laDate=20211213</a> will help us. </p>
<p>It has the same <strong>sign</strong> variable, but it has another variable <strong>laDate</strong> which takes the date in <strong>YYYYMMDD</strong> format. </p>
<p>Now, we're ready to create different functions to fetch horoscope data. Create a <code>utils.py</code> file and follow along.</p>
<h3 id="heading-howe-to-get-a-horoscope-for-the-day">Howe to Get a Horoscope for the Day</h3>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> requests
<span class="hljs-keyword">from</span> bs4 <span class="hljs-keyword">import</span> BeautifulSoup


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_horoscope_by_day</span>(<span class="hljs-params">zodiac_sign: int, day: str</span>):</span>
    <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> <span class="hljs-string">"-"</span> <span class="hljs-keyword">in</span> day:
        res = requests.get(<span class="hljs-string">f"https://www.horoscope.com/us/horoscopes/general/horoscope-general-daily-<span class="hljs-subst">{day}</span>.aspx?sign=<span class="hljs-subst">{zodiac_sign}</span>"</span>)
    <span class="hljs-keyword">else</span>:
        day = day.replace(<span class="hljs-string">"-"</span>, <span class="hljs-string">""</span>)
        res = requests.get(<span class="hljs-string">f"https://www.horoscope.com/us/horoscopes/general/horoscope-archive.aspx?sign=<span class="hljs-subst">{zodiac_sign}</span>&amp;laDate=<span class="hljs-subst">{day}</span>"</span>)
    soup = BeautifulSoup(res.content, <span class="hljs-string">'html.parser'</span>)
    data = soup.find(<span class="hljs-string">'div'</span>, attrs={<span class="hljs-string">'class'</span>: <span class="hljs-string">'main-horoscope'</span>})
    <span class="hljs-keyword">return</span> data.p.text
</code></pre>
<p>We have created our first function which accepts two arguments – an integer <strong>zodiac_sign</strong> and a string <strong>day</strong>. The day can either be today, tomorrow, yesterday or any custom date before today in the format YYYY-MM-DD. </p>
<p>If the day is not a custom date, it won't have the hyphen(-) symbol in it. So, we have put a condition for the same. </p>
<p>If there is no hyphen symbol, we make a GET request on <code>https://www.horoscope.com/us/horoscopes/general/horoscope-general-daily-{_day_}.aspx?sign={_zodiac_sign_}</code>. Else first, we change the date from YYYY-MM-DD to YYYYMMDD format. </p>
<p>Then we make a GET request on <code>https://www.horoscope.com/us/horoscopes/general/horoscope-archive.aspx?sign={_zodiac_sign_}&amp;laDate={_day_}</code>. </p>
<p>After that, we pull the HTML data from the response content of the page using BeautifulSoup. Now we need to get the horoscope text from this HTML code. If you inspect the code of any of the webpage, you'll find this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/12/screenshot-2021-12-07-081318_nwhwwf.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>The horoscope text is contained in a <strong>div</strong> with the class <strong>main-horoscope</strong>. Thus we use the <code>soup.find()</code> function to extract the paragraph text string, and return it.</p>
<h3 id="heading-how-to-get-a-horoscope-for-the-week">How to Get a Horoscope for the Week</h3>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_horoscope_by_week</span>(<span class="hljs-params">zodiac_sign: int</span>):</span>
    res = requests.get(<span class="hljs-string">f"https://www.horoscope.com/us/horoscopes/general/horoscope-general-weekly.aspx?sign=<span class="hljs-subst">{zodiac_sign}</span>"</span>)
    soup = BeautifulSoup(res.content, <span class="hljs-string">'html.parser'</span>)
    data = soup.find(<span class="hljs-string">'div'</span>, attrs={<span class="hljs-string">'class'</span>: <span class="hljs-string">'main-horoscope'</span>})
    <span class="hljs-keyword">return</span> data.p.text
</code></pre>
<p>The above function is quite similar to the previous one. We have just changed the URL to <code>https://www.horoscope.com/us/horoscopes/general/horoscope-general-weekly.aspx?sign={_zodiac_sign_}</code>.</p>
<h3 id="heading-how-to-get-a-horoscope-for-the-month">How to Get a Horoscope for the Month</h3>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_horoscope_by_month</span>(<span class="hljs-params">zodiac_sign: int</span>):</span>
    res = requests.get(<span class="hljs-string">f"https://www.horoscope.com/us/horoscopes/general/horoscope-general-monthly.aspx?sign=<span class="hljs-subst">{zodiac_sign}</span>"</span>)
    soup = BeautifulSoup(res.content, <span class="hljs-string">'html.parser'</span>)
    data = soup.find(<span class="hljs-string">'div'</span>, attrs={<span class="hljs-string">'class'</span>: <span class="hljs-string">'main-horoscope'</span>})
    <span class="hljs-keyword">return</span> data.p.text
</code></pre>
<p>This function is also similar to the other two except the URL which has now been changed to <code>https://www.horoscope.com/us/horoscopes/general/horoscope-general-monthly.aspx?sign={_zodiac_sign_}</code>.</p>
<h2 id="heading-how-to-create-api-routes">How to Create API Routes</h2>
<p>We'll be using Flask-RESTX to create our API routes. The API routes will look like these:</p>
<ul>
<li>For daily or custom dates:<code>/api/v1/get-horoscope/daily?day=today&amp;sign=capricorn</code> or <code>api/v1/get-horoscope/daily?day=2022-12-14&amp;sign=capricorn</code></li>
<li>For weekly: <code>api/v1/get-horoscope/weekly?sign=capricorn</code></li>
<li>For monthly: <code>api/v1/get-horoscope/monthly?sign=capricorn</code></li>
</ul>
<p>We have two query parameters in the URLs: <strong>day</strong> and <strong>sign</strong>. The <strong>day</strong> parameter can take values like today, yesterday, or custom dates like 2022-12-14. The <strong>sign</strong> parameter will take the zodiac sign name which can be in uppercase or lowercase, it won't matter.</p>
<p>To parse the query parameters from the URL, Flask-RESTX has built-in support for request data validation using a library similar to <a target="_blank" href="https://docs.python.org/3/library/argparse.html#module-argparse"><strong>argparse</strong></a> called <strong>reqparse</strong>. To add arguments in the URL, we'll use <strong>add_argument</strong> method of the <em>RequestParser</em> class.</p>
<pre><code class="lang-python">parser = reqparse.RequestParser()
parser.add_argument(<span class="hljs-string">'sign'</span>, type=str, required=<span class="hljs-literal">True</span>)
</code></pre>
<p>The <code>type</code> parameter will take the type of parameter. The <code>required=True</code> makes the query parameter mandatory to be passed. </p>
<p>Now, we need another query parameter day. But this parameter will be used only in the daily horoscope URL. </p>
<p>Instead of rewriting arguments we can write a parent parser containing all the shared arguments and then extend the parser with <a target="_blank" href="https://flask-restplus.readthedocs.io/en/stable/api.html#flask_restplus.reqparse.RequestParser.copy"><code>copy()</code></a>.</p>
<pre><code class="lang-python">parser_copy = parser.copy()
parser_copy.add_argument(<span class="hljs-string">'day'</span>, type=str, required=<span class="hljs-literal">True</span>)
</code></pre>
<p>The <code>parser_copy</code> will not only contain <strong>day</strong>, but also <strong>sign</strong>. That is what we'll require for the daily horoscope.</p>
<p>The main building blocks provided by Flask-RESTX are resources. Resources are built on top of <a target="_blank" href="https://flask.palletsprojects.com/en/2.0.x/views/">Flask pluggable views</a>, giving you easy access to multiple HTTP methods just by defining methods on your resource. </p>
<p>Let's create the <em>DailyHoroscopeAPI</em> class that inherits the <em>Resource</em> class from <code>flask_restx</code>.</p>
<pre><code class="lang-python"><span class="hljs-meta">@ns.route('/get-horoscope/daily')</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DailyHoroscopeAPI</span>(<span class="hljs-params">Resource</span>):</span>
    <span class="hljs-string">'''Shows daily horoscope of zodiac signs'''</span>
<span class="hljs-meta">    @ns.doc(parser=parser_copy)</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get</span>(<span class="hljs-params">self</span>):</span>
        args = parser_copy.parse_args()
        day = args.get(<span class="hljs-string">'day'</span>)
        zodiac_sign = args.get(<span class="hljs-string">'sign'</span>)
        <span class="hljs-keyword">try</span>:
            zodiac_num = ZODIAC_SIGNS[zodiac_sign.capitalize()]
            <span class="hljs-keyword">if</span> <span class="hljs-string">"-"</span> <span class="hljs-keyword">in</span> day:
                datetime.strptime(day, <span class="hljs-string">'%Y-%m-%d'</span>)
            horoscope_data = get_horoscope_by_day(zodiac_num, day)
            <span class="hljs-keyword">return</span> jsonify(success=<span class="hljs-literal">True</span>, data=horoscope_data, status=<span class="hljs-number">200</span>)
        <span class="hljs-keyword">except</span> KeyError:
            <span class="hljs-keyword">raise</span> NotFound(<span class="hljs-string">'No such zodiac sign exists'</span>)
        <span class="hljs-keyword">except</span> AttributeError:
            <span class="hljs-keyword">raise</span> BadRequest(
                <span class="hljs-string">'Something went wrong, please check the URL and the arguments.'</span>)
        <span class="hljs-keyword">except</span> ValueError:
            <span class="hljs-keyword">raise</span> BadRequest(<span class="hljs-string">'Please enter day in correct format: YYYY-MM-DD'</span>)
</code></pre>
<p>The <code>@ns.route()</code> decorator sets the API route. Inside the <em>DailyHoroscopeAPI</em> class, we have the <strong>get</strong> method that will handle the GET requests. The <code>@ns.doc()</code> decorator will help us add the query parameters on the URL. </p>
<p>To get the values of query parameters, we'll use the <strong>parse_args()</strong> method that will return us a dictionary like this:</p>
<pre><code class="lang-bash">{<span class="hljs-string">'sign'</span>: <span class="hljs-string">'capricorn'</span>, <span class="hljs-string">'day'</span>: <span class="hljs-string">'2022-12-14'</span>}
</code></pre>
<p>We can then get the values using the keys <strong>day</strong> and <strong>sign</strong>.</p>
<p>As defined in the beginning, we'll have a ZODIAC_SIGNS dictionary. We use a <strong>try-except</strong> block to handle the request. If the zodiac sign is not in the dictionary, a <em>KeyError</em> Exception is raised. In that case, we respond with a <em>NotFound</em> error (Error 404). </p>
<p>Also, if the <strong>day</strong> parameter has a hyphen in it, we try to match the date format with YYYY-MM-DD. If it's not in that format, we raise a <em>BadRequest</em> error (Error 400). If the <strong>day</strong> doesn't contain a hyphen, we directly call the <code>get_horoscope_by_day()</code> method with the <strong>sign</strong> and <strong>day</strong> arguments. </p>
<p>If some gibberish is passed as the parameter value, an <em>AttributeError</em> is raised. In that case, we raise a <em>BadRequest</em> error.</p>
<p>The other two routes are also quite similar to the above one. The difference is, we don't need a day parameter here. So, instead of using <code>parser_copy</code>, we'll use <code>parser</code> here.</p>
<pre><code class="lang-python"><span class="hljs-meta">@ns.route('/get-horoscope/weekly')</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">WeeklyHoroscopeAPI</span>(<span class="hljs-params">Resource</span>):</span>
    <span class="hljs-string">'''Shows weekly horoscope of zodiac signs'''</span>
<span class="hljs-meta">    @ns.doc(parser=parser)</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get</span>(<span class="hljs-params">self</span>):</span>
        args = parser.parse_args()
        zodiac_sign = args.get(<span class="hljs-string">'sign'</span>)
        <span class="hljs-keyword">try</span>:
            zodiac_num = ZODIAC_SIGNS[zodiac_sign.capitalize()]
            horoscope_data = get_horoscope_by_week(zodiac_num)
            <span class="hljs-keyword">return</span> jsonify(success=<span class="hljs-literal">True</span>, data=horoscope_data, status=<span class="hljs-number">200</span>)
        <span class="hljs-keyword">except</span> KeyError:
            <span class="hljs-keyword">raise</span> NotFound(<span class="hljs-string">'No such zodiac sign exists'</span>)
        <span class="hljs-keyword">except</span> AttributeError:
            <span class="hljs-keyword">raise</span> BadRequest(<span class="hljs-string">'Something went wrong, please check the URL and the arguments.'</span>)


<span class="hljs-meta">@ns.route('/get-horoscope/monthly')</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MonthlyHoroscopeAPI</span>(<span class="hljs-params">Resource</span>):</span>
    <span class="hljs-string">'''Shows monthly horoscope of zodiac signs'''</span>
<span class="hljs-meta">    @ns.doc(parser=parser)</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get</span>(<span class="hljs-params">self</span>):</span>
        args = parser.parse_args()
        zodiac_sign = args.get(<span class="hljs-string">'sign'</span>)
        <span class="hljs-keyword">try</span>:
            zodiac_num = ZODIAC_SIGNS[zodiac_sign.capitalize()]
            horoscope_data = get_horoscope_by_month(zodiac_num)
            <span class="hljs-keyword">return</span> jsonify(success=<span class="hljs-literal">True</span>, data=horoscope_data, status=<span class="hljs-number">200</span>)
        <span class="hljs-keyword">except</span> KeyError:
            <span class="hljs-keyword">raise</span> NotFound(<span class="hljs-string">'No such zodiac sign exists'</span>)
        <span class="hljs-keyword">except</span> AttributeError:
            <span class="hljs-keyword">raise</span> BadRequest(<span class="hljs-string">'Something went wrong, please check the URL and the arguments.'</span>)
</code></pre>
<p>Now our routes are done. To test the APIs, you can use the Swagger documentation available on the <code>/</code> route, or you can use <a target="_blank" href="https://www.postman.com/">Postman</a>. Let's run the server and test it.</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/yggJPOqr6jc" 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>You can also deploy the project on a public server so that other developers can access and use the API too.</p>
<h2 id="heading-wrapping-up">Wrapping up</h2>
<p>In this tutorial, we learned how to scrape data from a website using requests and Beautiful Soup. Then we created an API using Flask and Flask-RESTX. </p>
<p>If you wish to learn how to interact with APIs using Python, check out <a target="_blank" href="https://www.freecodecamp.org/news/how-to-interact-with-web-services-using-python/">this guide</a>.</p>
<p>I hope you enjoyed it – and thanks for reading!</p>
<p>Code for the tutorial: <a target="_blank" href="https://github.com/ashutoshkrris/Horoscope-API">https://github.com/ashutoshkrris/Horoscope-API</a> </p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Dockerize a Flask Application ]]>
                </title>
                <description>
                    <![CDATA[ By Ondiek Elijah Ochieng These days, developers need to develop, ship, and run applications quicker than ever. And fortunately, there's a tool that helps you do that – Docker. With Docker, you can now easily ship, test, and deploy your code quickly w... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-dockerize-a-flask-app/</link>
                <guid isPermaLink="false">66d4608bc7632f8bfbf1e46d</guid>
                
                    <category>
                        <![CDATA[ Docker ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Docker Containers ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Flask Framework ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Thu, 11 Nov 2021 16:04:40 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/11/flask-docker.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Ondiek Elijah Ochieng</p>
<p>These days, developers need to develop, ship, and run applications quicker than ever. And fortunately, there's a tool that helps you do that – Docker.</p>
<p>With Docker, you can now easily ship, test, and deploy your code quickly while maintaining full control over your infrastructure. It significantly reduces how long it takes to get from writing code to running it in production.</p>
<p>This article will show you how to make a basic Docker image and run it as a container. For the demonstration, we'll use Flask as our web framework and Docker for image creation and containerization. You'll also learn a few Docker commands that are commonly used.</p>
<h2 id="heading-what-is-flask">What is Flask?</h2>
<p><a target="_blank" href="https://flask.palletsprojects.com/en/2.0.x/"><strong>Flask</strong></a> is a popular Python micro web framework that helps you develop lightweight web applications and APIs quickly and easily. </p>
<p>As a web framework, it provides greater flexibility, customization, and scalability for simple web applications while remaining highly compatible with cutting-edge technologies.</p>
<h2 id="heading-what-is-docker">What is Docker?</h2>
<p>Docker is a tool that makes it easier to create, deploy, and run applications using containers.</p>
<p>A <strong>docker container</strong> is a collection of dependencies and code organized as software that enables applications to run quickly and efficiently in a range of computing environments.</p>
<p>A <strong>docker image</strong>, on the other hand, is a blueprint that specifies how to run an application. In order for Docker to build images automatically, a set of instructions must be stored in a special file known as a <strong>Dockerfile</strong>. </p>
<p>The instructions in this file are executed by the user on the command line interface in order to create an image. (Source: <a target="_blank" href="https://www.docker.com/resources/what-container">docker.com</a>)</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/11/docker-illustration-2.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-how-to-set-up-the-project">How to Set Up the Project</h2>
<h3 id="heading-basic-directory-structure">Basic directory structure</h3>
<p>After completing the following steps, our application directory structure will look like this:</p>
<p><strong>flask-docker</strong><br>├── app.py<br>├── Dockerfile<br>├── requirements.txt<br>└── <strong>venv</strong></p>
<p>In this section, we'll go over how to create an application with a structure similar to the one shown above. You can find a detailed guide on how to create or install this project <a target="_blank" href="https://github.com/Dev-Elie/Flask-Docker-App/blob/main/README.md#create-a-new-application-from-scratch">here</a>.</p>
<p>Assuming you followed the installation instructions correctly and have an active virtual environment with Flask installed, we will now modify the two files created in the GitHub readme as follows.</p>
<h3 id="heading-how-to-modify-apppy">How to modify app.py</h3>
<p>Let's add the following lines of code to our <strong>app.py</strong>:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> Flask
app = Flask(__name__)

<span class="hljs-meta">@app.route('/')</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">hello_geek</span>():</span>
    <span class="hljs-keyword">return</span> <span class="hljs-string">'&lt;h1&gt;Hello from Flask &amp; Docker&lt;/h2&gt;'</span>


<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>:
    app.run(debug=<span class="hljs-literal">True</span>)
</code></pre>
<p>Now, if we run <strong>python app.py</strong> on the command line to test our Flask app, we should get results similar to the ones shown below:</p>
<pre><code class="lang-bash"> * Serving Flask app <span class="hljs-string">'app'</span> (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it <span class="hljs-keyword">in</span> a production deployment.
   Use a production WSGI server instead.
 * Debug mode: on
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
 * Restarting with <span class="hljs-built_in">stat</span>
 * Debugger is active!
 * Debugger PIN: 316-584-348
</code></pre>
<h3 id="heading-how-to-modify-the-dockerfile">How to modify the Dockerfile</h3>
<pre><code class="lang-dockerfile"><span class="hljs-comment"># syntax=docker/dockerfile:1</span>

<span class="hljs-keyword">FROM</span> python:<span class="hljs-number">3.8</span>-slim-buster

<span class="hljs-keyword">WORKDIR</span><span class="bash"> /python-docker</span>

<span class="hljs-keyword">COPY</span><span class="bash"> requirements.txt requirements.txt</span>
<span class="hljs-keyword">RUN</span><span class="bash"> pip3 install -r requirements.txt</span>

<span class="hljs-keyword">COPY</span><span class="bash"> . .</span>

<span class="hljs-keyword">CMD</span><span class="bash"> [ <span class="hljs-string">"python3"</span>, <span class="hljs-string">"-m"</span> , <span class="hljs-string">"flask"</span>, <span class="hljs-string">"run"</span>, <span class="hljs-string">"--host=0.0.0.0"</span>]</span>
</code></pre>
<p>Before we build an image for the application we just created, let's first understand what the lines of code in the Docker file above mean and what role they play.</p>
<p>The below code should be the first line of every Dockerfile – it tells the Docker builder what syntax to use while parsing the Dockerfile and the location of the Docker syntax file. (<a target="_blank" href="https://docs.docker.com/engine/reference/builder/#syntax">Source</a>)</p>
<pre><code class="lang-dockerfile"><span class="hljs-comment"># syntax=docker/dockerfile:1</span>
</code></pre>
<p>While it is possible to create our own base images, there is no need to go that far because Docker allows us to inherit existing images. The following line tells Docker which base image to use — in this case, a Python image.</p>
<pre><code>FROM python:<span class="hljs-number">3.8</span>-slim-buster
</code></pre><p>To keep things organized, we also tell Docker which folder to use for the rest of the operations, so we use a relative path as shown below. </p>
<p>In this case, we're telling Docker to use the same directory and name for the rest of its operations — it's a directory contained within our container image.</p>
<pre><code>WORKDIR /python-docker
</code></pre><p>In the fourth and fifth lines, we tell Docker to copy the contents of our requirements.txt file into the container image's requirements.txt file. Then run pip install to install all the dependencies in the same file to be used by the image.</p>
<pre><code>COPY requirements.txt requirements.txt
RUN pip3 install -r requirements.txt
</code></pre><p>Continuing with the copying, we now copy the remainder of the files in our local working directory to the directory in the docker image.</p>
<pre><code>COPY . .
</code></pre><p><img src="https://www.freecodecamp.org/news/content/images/2021/11/docker-illustration.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Our image so far has all of the files that are similar to those in our local working directory. Our next task is to assist Docker in understanding how to run this image inside a container. </p>
<p>This line specifically instructs Docker to run our Flask app as a module, as indicated by the "-m" tag. Then it instructs Docker to make the container available externally, such as from our browser, rather than just from within the container. We pass the host port:</p>
<pre><code>CMD [ <span class="hljs-string">"python3"</span>, <span class="hljs-string">"-m"</span> , <span class="hljs-string">"flask"</span>, <span class="hljs-string">"run"</span>, <span class="hljs-string">"--host=0.0.0.0"</span>]
</code></pre><p>Since we had,</p>
<pre><code class="lang-python"><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>:
    app.run(debug=<span class="hljs-literal">True</span>)
</code></pre>
<p>Because we had the "if" statement in our application file, this will be true if we run this module as a standalone program. As a result, it can function as a module imported by another program or as a standalone program, but it will only execute the code in the if statement if run as a program. (<a target="_blank" href="https://stackoverflow.com/a/1973391/12943692">Source</a>)</p>
<h2 id="heading-how-to-build-a-docker-image">How to Build a Docker Image</h2>
<p>After that, all that remains is to build our image. Using <strong><code>docker build</code></strong>, we can now enlist Docker's help in building the image. You can combine the build command with other tags, such as the "--tag" flag, to specify the image name.</p>
<pre><code>docker build --tag python-docker .
</code></pre><h3 id="heading-how-to-run-an-image-as-a-container">How to run an image as a container</h3>
<p>Running an image inside a container is as simple as building one. But before we do so, we'd like to see what other images are available in our environment. To view images from the command line, execute the following:</p>
<pre><code>docker images
</code></pre><p>If the above command finds any images, the output should look something like this:</p>
<pre><code class="lang-bash">REPOSITORY      TAG       IMAGE ID       CREATED             SIZE
python-docker   latest    cd52b70b361a   About an hour ago   912MB
headless-cms    latest    e8b253e230ee   43 hours ago        937MB
scrappy         latest    3e7ac0d44890   7 weeks ago         904MB
python          3.9.2     587b1bc803b3   7 months ago        885MB
</code></pre>
<p>Now we can choose which image to run. Using the <strong><code>docker run</code></strong> command, we can run an image by passing the image's name as a parameter.</p>
<pre><code class="lang-docker">docker <span class="hljs-keyword">run</span>
</code></pre>
<p>While running the above command, you'll notice that on the command line it indicates that the application is running. But when you enter <a target="_blank" href="http://localhost:5000/"><code>http://localhost:5000/</code></a> on the browser, the greeting will be:</p>
<blockquote>
<p>This site can’t be reached localhost refused to connect.</p>
</blockquote>
<p>Regardless of whether the container is running, it is doing so in isolation mode and cannot connect to localhost:5000.</p>
<p>The best solution is to run the image in detached mode. Because we need to view this application in the browser rather than the container, we'll modify our docker run and add two additional tags: "-d" to run it in detached mode and "-p" to specify the port to be exposed. </p>
<p>The docker run command will now be formatted as follows:</p>
<pre><code>docker run -d -p <span class="hljs-number">5000</span>:<span class="hljs-number">5000</span> python-docker
</code></pre><p>This time, we'll see the following output if we run it in detached mode and visit localhost at port 5000:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/11/d.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>We can use the following command to see which containers are currently running:</p>
<pre><code>docker ps
</code></pre><p>The output is as follows:</p>
<pre><code>CONTAINER ID   IMAGE           COMMAND                  CREATED         STATUS         PORTS                    NAMES
a173935297cd   python-docker   <span class="hljs-string">"python3 -m flask ru…"</span>   <span class="hljs-number">5</span> minutes ago   Up <span class="hljs-number">5</span> minutes   <span class="hljs-number">0.0</span><span class="hljs-number">.0</span><span class="hljs-number">.0</span>:<span class="hljs-number">5000</span>-&gt;<span class="hljs-number">5000</span>/tcp   happy_wescoff
</code></pre><p>To stop the currently running container, we execute this command:</p>
<pre><code>docker stop &lt;container-name&gt;
</code></pre><p>Another useful command to have when working with Docker is this one:</p>
<pre><code>docker container prune
</code></pre><p>It removes unused resources, freeing up space and keeping your system clean.</p>
<p>And that's it!</p>
<p>Thank you for taking the time to read this article. Please share, thank me in a tweet, and don't forget to follow me on Twitter <a target="_blank" href="https://twitter.com/dev_elie">@dev_elie</a>. </p>
<p>You can find more information on Docker and Python in the official <a target="_blank" href="https://docs.docker.com/language/python/">documentation</a>. I'll see you next time.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Authenticate Users in Flask with Flask-Login ]]>
                </title>
                <description>
                    <![CDATA[ By Ondiek Elijah Ochieng When you're developing applications for the general public, it's important to protect your users' credentials and information. This means you need to know about code structure and how to implement various security measures. I... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-authenticate-users-in-flask/</link>
                <guid isPermaLink="false">66d4608ab3016bf139028d7f</guid>
                
                    <category>
                        <![CDATA[ Application Security ]]>
                    </category>
                
                    <category>
                        <![CDATA[ authentication ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Flask Framework ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 01 Nov 2021 20:00:24 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/10/Auth-in-Flask.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Ondiek Elijah Ochieng</p>
<p>When you're developing applications for the general public, it's important to protect your users' credentials and information. This means you need to know about code structure and how to implement various security measures.</p>
<p>In this article, we'll walk through the steps to create a user authentication web app with Flask, a micro web framework. For authentication, we'll use the Python library <code>flask_login</code>.</p>
<p>This app includes features such as form validations, account creation, and login/logout functionality for authenticated users.</p>
<h2 id="heading-application-setup-and-installation">Application Setup and Installation</h2>
<p>You can find a comprehensive guide on setting up and installing the project on my <a target="_blank" href="https://github.com/Dev-Elie/User-Authentication-in-Flask/tree/main#readme">GitHub</a> repository.</p>
<h3 id="heading-basic-application-structure">Basic Application Structure</h3>
<p>For this application, we'll have a virtual environment in its own directory, as well as a folder containing the main application files. Here's an overview of the app's structure:</p>
<p><strong>.</strong><br>├── <strong>auth-app</strong><br>│   ├── app.py<br>│   ├── database.db<br>│   ├── forms.py<br>│   ├── manage.py<br>│   ├── <strong>migrations</strong><br>│   ├── models.py<br>│   ├── requirements.txt<br>│   ├── routes.py<br>│   ├── <strong>run</strong><br>│   ├── <strong>static</strong><br>│   └── <strong>templates</strong><br>│       ├── auth.html<br>│       ├── base.html<br>│       └── index.html<br>└── <strong>venv</strong></p>
<h3 id="heading-application-factory">Application Factory</h3>
<p>To kick it off, we'll create an application factory function inside the app.py file and call it <code>create_app</code>. This is vital for any Flask app.</p>
<p>Also, we need to make some libraries available for use within our project, so we'll import the following:</p>
<p><strong>app.py</strong></p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> Flask
<span class="hljs-keyword">from</span> flask_sqlalchemy <span class="hljs-keyword">import</span> SQLAlchemy
<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_login <span class="hljs-keyword">import</span> (
    UserMixin,
    login_user,
    LoginManager,
    current_user,
    logout_user,
    login_required,
)
</code></pre>
<p>We imported Flask, SQLAlchemy to help our Python application communicate with a database, Bcrypt for password hashing, Migrate for database migrations, and several other methods from Flask-Login for session management.</p>
<pre><code class="lang-python">login_manager = LoginManager()
login_manager.session_protection = <span class="hljs-string">"strong"</span>
login_manager.login_view = <span class="hljs-string">"login"</span>
login_manager.login_message_category = <span class="hljs-string">"info"</span>
</code></pre>
<p>To use flask_login, we'll create an instance as shown above. We'll do the same for SQLAlchemy, Migrate, and Bcrypt.</p>
<pre><code class="lang-python">db = SQLAlchemy()
migrate = Migrate()
bcrypt = Bcrypt()
</code></pre>
<p>Instead of creating our Flask instance globally, we'll do so within a function because doing so globally becomes difficult as the project grows. </p>
<p>The benefit of doing this within a function is that it allows for multiple application instances (also during testing). (Source: <a target="_blank" href="https://flask.palletsprojects.com/en/2.0.x/patterns/appfactories/#application-factories">flask.palletsprojects.com</a>)</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">create_app</span>():</span>
    app = Flask(__name__)

    app.secret_key = <span class="hljs-string">'secret-key'</span>
    app.config[<span class="hljs-string">'SQLALCHEMY_DATABASE_URI'</span>] = <span class="hljs-string">"sqlite:///database.db"</span>
    app.config[<span class="hljs-string">'SQLALCHEMY_TRACK_MODIFICATIONS'</span>] = <span class="hljs-literal">True</span>

    login_manager.init_app(app)
    db.init_app(app)
    migrate.init_app(app, db)
    bcrypt.init_app(app)

    <span class="hljs-keyword">return</span> app
</code></pre>
<p>Flask-Login also requires that we set a secret key in order to function. Also, you'll notice that we have our initializations inside the application factory. We do this to avoid the extensions initially binding themselves to the application, as explained <a target="_blank" href="https://flask.palletsprojects.com/en/2.0.x/patterns/appfactories/#factories-extensions">here</a>.</p>
<p>Now that we've completed our basic application factory, it's time to declare our User model. In the user table, we only need email, username, and password columns for this application.</p>
<p><strong>models.py</strong></p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> app <span class="hljs-keyword">import</span> db
<span class="hljs-keyword">from</span> flask_login <span class="hljs-keyword">import</span> UserMixin

<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>
    __tablename__ = <span class="hljs-string">"user"</span>

    id = db.Column(db.Integer, primary_key=<span class="hljs-literal">True</span>)
    username = db.Column(db.String(<span class="hljs-number">80</span>), unique=<span class="hljs-literal">True</span>, nullable=<span class="hljs-literal">False</span>)
    email = db.Column(db.String(<span class="hljs-number">120</span>), unique=<span class="hljs-literal">True</span>, nullable=<span class="hljs-literal">False</span>)
    pwd = db.Column(db.String(<span class="hljs-number">300</span>), nullable=<span class="hljs-literal">False</span>, unique=<span class="hljs-literal">True</span>)

    <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">'&lt;User %r&gt;'</span> % self.username
</code></pre>
<p>We import db, an instance of SQLAlchemy, and a UserMixin subclass from Flask-Login in the above code snippet. Our work is simplified by using the UserMixin, which allows us to use methods such as <strong>is_authenticated()</strong>, <strong>is_active()</strong>, <strong>is_anonymous()</strong>, and <strong>get_id ()</strong>.</p>
<p>If we don't include the UserMixin in our User model, we'll get errors like <code>'User' object has no attribute 'is_active'</code>.</p>
<p>We currently have a User model, but we haven't yet created the table. To do this, run <code>python manage.py</code> on your terminal inside your project directory—assuming you got the setup right, installed the packages in the requirements.txt file, and have an active virtual environment.</p>
<p><strong>manage.py</strong></p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">deploy</span>():</span>
    <span class="hljs-string">"""Run deployment tasks."""</span>
    <span class="hljs-keyword">from</span> app <span class="hljs-keyword">import</span> create_app,db
    <span class="hljs-keyword">from</span> flask_migrate <span class="hljs-keyword">import</span> upgrade,migrate,init,stamp
    <span class="hljs-keyword">from</span> models <span class="hljs-keyword">import</span> User

    app = create_app()
    app.app_context().push()
    db.create_all()

    <span class="hljs-comment"># migrate database to latest revision</span>
    init()
    stamp()
    migrate()
    upgrade()

deploy()
</code></pre>
<p>The <code>deploy</code> function imports the <code>create_app</code> function from the <code>app.py</code> file, Flask-Migrate migration methods, and the User model. We then ensure that we are working within an application context, from which we can now call <code>db.create all()</code>, which will take care of our table creation.</p>
<p>We still need to set up the login and registration forms. First, we need to prepare the two Flask forms before rendering them on the template. The configuration for the forms is shown below. To keep this article neat and precise, I'll omit the import lines. For the excluded import lines, see the <a target="_blank" href="https://github.com/Dev-Elie/User-Authentication-in-Flask">GitHub</a> repository.</p>
<h3 id="heading-formspy">forms.py</h3>
<p><strong>a). Registration form</strong></p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">register_form</span>(<span class="hljs-params">FlaskForm</span>):</span>
    username = StringField(
        validators=[
            InputRequired(),
            Length(<span class="hljs-number">3</span>, <span class="hljs-number">20</span>, message=<span class="hljs-string">"Please provide a valid name"</span>),
            Regexp(
                <span class="hljs-string">"^[A-Za-z][A-Za-z0-9_.]*$"</span>,
                <span class="hljs-number">0</span>,
                <span class="hljs-string">"Usernames must have only letters, "</span> <span class="hljs-string">"numbers, dots or underscores"</span>,
            ),
        ]
    )
    email = StringField(validators=[InputRequired(), Email(), Length(<span class="hljs-number">1</span>, <span class="hljs-number">64</span>)])
    pwd = PasswordField(validators=[InputRequired(), Length(<span class="hljs-number">8</span>, <span class="hljs-number">72</span>)])
    cpwd = PasswordField(
        validators=[
            InputRequired(),
            Length(<span class="hljs-number">8</span>, <span class="hljs-number">72</span>),
            EqualTo(<span class="hljs-string">"pwd"</span>, message=<span class="hljs-string">"Passwords must match !"</span>),
        ]
    )
</code></pre>
<p>In the above code snippet, we're simply applying validations to the required fields imported from <code>wtforms</code> and assigning them to the form field variable names. </p>
<pre><code class="lang-python">    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">validate_email</span>(<span class="hljs-params">self, email</span>):</span>
        <span class="hljs-keyword">if</span> User.query.filter_by(email=email.data).first():
            <span class="hljs-keyword">raise</span> ValidationError(<span class="hljs-string">"Email already registered!"</span>)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">validate_uname</span>(<span class="hljs-params">self, uname</span>):</span>
        <span class="hljs-keyword">if</span> User.query.filter_by(username=username.data).first():
            <span class="hljs-keyword">raise</span> ValidationError(<span class="hljs-string">"Username already taken!"</span>)
</code></pre>
<p>To speed up the validation process, we need to reduce the load and time required for server-side validation. To accomplish this, we add the above lines of code—email and username validation to our registration form class so that it is handled on the client side.</p>
<p><strong>b). Login form</strong></p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">login_form</span>(<span class="hljs-params">FlaskForm</span>):</span>
    email = StringField(validators=[InputRequired(), Email(), Length(<span class="hljs-number">1</span>, <span class="hljs-number">64</span>)])
    pwd = PasswordField(validators=[InputRequired(), Length(min=<span class="hljs-number">8</span>, max=<span class="hljs-number">72</span>)])
    <span class="hljs-comment"># Placeholder labels to enable form rendering</span>
    username = StringField(
        validators=[Optional()]
    )
</code></pre>
<p>To make the form fields visible on the template, we must pass the form object to it via the route rendering that template. Now it's time to define our application's various routes. I'll also leave out the import lines for this section.</p>
<h3 id="heading-routespy">routes.py</h3>
<p>It is important to provide a user loader callback when using Flask-Login. This keeps the current user object loaded in that current session based on the stored id.</p>
<pre><code class="lang-python"><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.get(int(user_id))
</code></pre>
<p>In the lines of code that follow, we simply define three routes for this application: home, login, and register. Notice how we create Flask form instances and then pass them along with the function return statement? We'll modify these routes later to handle our login and registration needs. We'll also add a logout route.</p>
<pre><code class="lang-python">app = create_app()

<span class="hljs-comment"># Home route</span>
<span class="hljs-meta">@app.route("/", methods=("GET", "POST"), strict_slashes=False)</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">index</span>():</span>
    <span class="hljs-keyword">return</span> render_template(<span class="hljs-string">"index.html"</span>,title=<span class="hljs-string">"Home"</span>)

<span class="hljs-comment"># Login route</span>
<span class="hljs-meta">@app.route("/login/", methods=("GET", "POST"), strict_slashes=False)</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">login</span>():</span>
    form = login_form()

    <span class="hljs-keyword">return</span> render_template(<span class="hljs-string">"auth.html"</span>,form=form)

<span class="hljs-comment"># Register route</span>
<span class="hljs-meta">@app.route("/register/", methods=("GET", "POST"), strict_slashes=False)</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">register</span>():</span>
    form = register_form()

    <span class="hljs-keyword">return</span> render_template(<span class="hljs-string">"auth.html"</span>,form=form)

<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>:
    app.run(debug=<span class="hljs-literal">True</span>)
</code></pre>
<p>It's time to write some HTML code. At this point, all we need is forms in the browser. <strong>NB</strong>: I'll still leave out some lines of code to keep this article concise. The complete files are available on <a target="_blank" href="https://github.com/Dev-Elie/User-Authentication-in-Flask">GitHub</a>, but for the time being, let's concentrate on the main areas of interest.</p>
<p><strong>auth.html</strong></p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">action</span>=<span class="hljs-string">"{{ request.path }}"</span> <span class="hljs-attr">method</span>=<span class="hljs-string">"POST"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"..."</span>&gt;</span>

{{ form.csrf_token }}

{% with messages = get_flashed_messages(with_categories=true) %}
<span class="hljs-comment">&lt;!-- Categories: success (green), info (blue), warning (yellow), danger (red) --&gt;</span>
{% if messages %}
{% 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 %}
{% endif %}
{% endwith %}

{% if request.path == '/register/' %}
{{ form.username(class_="form-control",placeholder="Username")}}

{% for error in form.username.errors %}
{{ error }}
{% endfor%}

{% endif%}

{{ form.email(class_="form-control",placeholder="Email")}}

{% for error in form.email.errors %}
{{ error }}
{% endfor%}

{{ form.pwd(class_="form-control",placeholder="Password")}}

{% for error in form.pwd.errors %}
{{ error }}
{% endfor%}

{% if request.path == '/register/' %}
{{ form.cpwd(class_="form-control",placeholder="Confirm Password")}}

{% for error in form.cpwd.errors %}
{{ error }}
{% endfor%}

{% endif%}

<span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-block btn-primary mb-3"</span>&gt;</span>
{{ btn_action }}
<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
{% if request.path != '/register/' %}
New here?
<span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"{{url_for('register')}}"</span>&gt;</span>Create account<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
{% else %}
Already have an account?
<span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"{{url_for('login')}}"</span>&gt;</span>Login<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
{% endif %}
<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
</code></pre>
<p>The HTML template shown above serves as both our login and registration form. And I just used a few jinja templating tricks.</p>
<p>As you can see above, the form action is set to <code>action="{{request.path}}"</code>, where <code>request.path</code> retrieves the path from which the request originated and assigns it as the value for the form action. This eliminates the need to hard code the specific paths. </p>
<p>We also set a csrf token variable which allows the form validation to proceed while preventing session riding attacks.</p>
<p>It also handles flashed messages. Bootstrap 5 alerts make it simple to flash different messages based on their category. The following is an example of what that does.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/10/error-msg.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>We simply print out the individual variable names from the form object to display the form fields. Here's an example from the above snippet:</p>
<p><code>{{ form.username(class_="form-control",placeholder="Username")}}</code></p>
<p>Another thing to consider is the use of <code>if...else</code> statements, such as in the following line of code:</p>
<p><code>{% if request.path == '/register/' %}</code></p>
<p>By hiding some fields based on the request path, we can easily switch between the login and registration forms.</p>
<p>Remember the validation checks that we applied to the form fields? Also, we'd like to notify the user if they fail to provide the required input – so we'll include some code for this. An example from the HTML form above is shown below. </p>
<p>The lines of code below will display the appropriate message to the user if any of the checks against the username are violated.</p>
<pre><code class="lang-html">{% for error in form.username.errors %}
{{ error }}
{% endfor%}
</code></pre>
<p>Here's an example of what that would look like:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/10/error-msg-2.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h3 id="heading-how-to-modify-routespy">How to modify routes.py</h3>
<p>In Flask, adding new users to the database is simple. To complete today's tutorial, we need to register, login, and logout users — that is, manage sessions.</p>
<p><strong>a). Registration route</strong></p>
<p>First and foremost, taking a closer look at the code snippet below for registering new users, we confirm that the form sending the data has passed all validation checks. So, <code>if form.validate_on_submit():</code></p>
<pre><code class="lang-python">    ...

    <span class="hljs-keyword">if</span> form.validate_on_submit():
        <span class="hljs-keyword">try</span>:
            email = form.email.data
            pwd = form.pwd.data
            username = form.username.data

            newuser = User(
                username=username,
                email=email,
                pwd=bcrypt.generate_password_hash(pwd),
            )

            db.session.add(newuser)
            db.session.commit()
            flash(<span class="hljs-string">f"Account Succesfully created"</span>, <span class="hljs-string">"success"</span>)
            <span class="hljs-keyword">return</span> redirect(url_for(<span class="hljs-string">"login"</span>))

        <span class="hljs-keyword">except</span> Exception <span class="hljs-keyword">as</span> e:
            flash(e, <span class="hljs-string">"danger"</span>)

      ...
</code></pre>
<p>If all of the checks pass, we get the values from the form fields, which are then passed to the User object, added to the database, and all of the changes are saved.</p>
<p>When the database is successfully updated with the new values, the user sees a success message. After that, the application redirects the user to the login page.</p>
<p>Any exceptions that may occur are caught and displayed to the user. This improves the user experience by displaying nicer alerts (and you can also modify the messages based on the exceptions).</p>
<p>It is not safe to store passwords in plain text because this increases the risk that user credentials will be compromised in the event of a breach. </p>
<p>The user password is hashed before being saved, and what is stored in the database is a highly encrypted combination of characters. We handled this with the help of Bcrypt. The hash is generated like this:</p>
<p><code>pwd=bcrypt.generate_password_hash(pwd)</code></p>
<p><strong>b). Login route</strong></p>
<pre><code class="lang-python">    <span class="hljs-keyword">if</span> form.validate_on_submit():
        <span class="hljs-keyword">try</span>:
            user = User.query.filter_by(email=form.email.data).first()
            <span class="hljs-keyword">if</span> check_password_hash(user.pwd, form.pwd.data):
                login_user(user)
                <span class="hljs-keyword">return</span> redirect(url_for(<span class="hljs-string">'index'</span>))
            <span class="hljs-keyword">else</span>:
                flash(<span class="hljs-string">"Invalid Username or password!"</span>, <span class="hljs-string">"danger"</span>)
        <span class="hljs-keyword">except</span> Exception <span class="hljs-keyword">as</span> e:
            flash(e, <span class="hljs-string">"danger"</span>)
</code></pre>
<p>After passing validation, the User model is queried to see if a user exists with the email provided. If this fails it displays an error message. But if it's validated, the second move is to compare the password issued with the hashed version of it. And if both match, access is granted and the user is redirected to the home page.</p>
<p><strong>c). Logout route</strong></p>
<pre><code class="lang-python"><span class="hljs-meta">@app.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()
    <span class="hljs-keyword">return</span> redirect(url_for(<span class="hljs-string">'login'</span>))
</code></pre>
<p>The above route, which redirects to the login page, handles the termination of active sessions.</p>
<p>And that's it! We've built our application with user authentication.</p>
<p>Thank you for reading. I hope you found this article useful. Continue to read, build, and best wishes. Don't forget to follow me on Twitter as well <a target="_blank" href="https://twitter.com/dev_elie"><strong>@dev_elie</strong></a><strong>.</strong></p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
