Building a Webapp with User Authentification using Flask
Published: 2021-08-27 21:51:04

In this article, I will be showing you how to build a simple web app with **user authentification** or **login** using flask.

###This app will have the following features:
1. Users will be able to sign up using their email addresses and also create a password.
2. Once a user is signed in, they are registered in the database.
3. If any user tries to sign in with credentials that already exist in the database, an error message will be returned notifying them.
4. The app will have a remember me function to remember users so they don't always have to enter their passwords to login to the app.
5. When logged in, a user will be able to see other routes of the app like profile and sign out.
6. When signed out, the user can only see the home, Login and signup routes.

##Alright lets get coding.

The first step is to fire up the IDE of choice. 
Then create a project folder and then set up a virtual environment in which we will add the different dependencies for the app.

Install the necessary packages such as **flask**, **flask-login**(which is used for the user login and authentication), **flask-sqlalchemy** which is used to create a database to store the data.


Once all that is set up, create a new python file and call it `init.py`. This will initialise the app.

Open the `init.py` file and import the following packages;

```
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager
```

**Flask** provides a lightweight framework for building our web app.
**SQLAlchemy** is used to create the database to store user data such as emails and passwords.
Checkout the official documentation [here](https://flask-sqlalchemy.palletsprojects.com/en/2.x/) to know about flask-SQLAlchemy.
**flask-login** provides user session management for flask. It handles common tasks such as logging in, logging out and remembering users' sessions . Be sure to check out the official flask-login documentation [here](https://flask-login.readthedocs.io/en/latest/) for more information about it.

Next, we will create a function to initialize the database using SQLAlchmemy as shown in the code snippet below.

Initialise SQLAlchemy so we can use it later.

`db = SQLAlchemy()`

Create a function called `create_app` and create the flask instance and also add other configurations for the database.

```
def create_app():
    app = Flask(__name__)
    app.secret_key = b'_5#y2L"F4Qz\k\xec]/'
    app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///users.db'
    db.init_app(app)
```

create a variable called `login_manager` to create a Login Manager instance to manage user login.

```
login_manager = LoginManager()
login_manager.login_view = 'auth.login'
login_manager.init_app(app) 
```

Then create another python file called `models.py` to store information about the users.

The model created is constituted of class which is translated into tables in our database. Each of the attributes are transformed into columns for the table.

```
class User(UserMixin, db.Model):
    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(100), unique=True)
    password = db.Column(db.String(100))
    name = db.Column(db.String(1000)
```

Open the **init.py** file again and import class **User** from **models.py**

Open a new python file called auth.py. This file will contain all the logic for our **auth routes** for example login and signup.

Import the neccesary packages first.

```
from flask import Blueprint, render_template, redirect, url_for, request, flash
from werkzeug.security import generate_password_hash, check_password_hash
from models import User
from flask_login import login_user, logout_user, login_required
from init import db
```
**Flash** is used to show messages to the user for example error messages.
**Blueprint** is a python package that can help structure a flask  application by grouping its functionality into reusable components. Read more about Blueprint package [here](https://realpython.com/flask-blueprint/).

In this file we will put all the auth routes with logic to add new users to the database ,remember the user and logout the user.

Here is the full file below 

`auth.py`

```
from flask import Blueprint, render_template, redirect, url_for, request, flash
from werkzeug.security import generate_password_hash, check_password_hash
from models import User
from flask_login import login_user, logout_user, login_required
from init import db

auth = Blueprint('auth', __name__)


@auth.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'GET':
        return render_template('login.html')
    else:
        email = request.form.get('email')
        password = request.form.get('password')
        remember = True if request.form.get('remember') else False
        user = User.query.filter_by(email=email).first()

        if not user:
            flash('Please sign up first!')
            return redirect(url_for('auth.signup'))
        elif not check_password_hash(user.password, password):
            flash('Please check your login details and try again.')
            return redirect(url_for('auth.login'))
        login_user(user, remember=remember)
        return redirect(url_for('main.profile'))


@auth.route('/signup', methods=['GET', 'POST'])
def signup():
    if request.method == 'GET':
        return render_template('signup.html')
    else:
        email = request.form.get('email')
        name = request.form.get('name')
        password = request.form.get('password')
        user = User.query.filter_by(email=email).first()

        if user:
            flash('Email already exists')
            return redirect(url_for('auth.signup'))
        new_user = User(email=email, name=name, password=generate_password_hash(password, method='SHA256'))

        db.session.add(new_user)
        db.session.commit()
        return redirect(url_for('auth.login'))


@auth.route('/logout')
@login_required
def logout():
    logout_user()
    return redirect(url_for('main.index'))
```

This is the full **init.py** file.

```
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager

db = SQLAlchemy()


def create_app():
    app = Flask(__name__)
    app.secret_key = b'_5#y2L"F4Qz\k\xec]/'
    app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///users.db'
    db.init_app(app)
    login_manager = LoginManager()
    login_manager.login_view = 'auth.login'
    login_manager.init_app(app)

    from models import User

    @login_manager.user_loader
    def load_user(user_id):
        return User.query.get(int(user_id))

    # blueprint for auth routes in the app
    from auth import auth as auth_blueprint
    app.register_blueprint(auth_blueprint)

    # blueprint for non auth routes in the app
    from main import main as main_blueprint
    app.register_blueprint(main_blueprint)

    return app
```

The `main.py` file
```
from flask import Blueprint, render_template
from flask_login import login_required, current_user
from init import create_app, db

main = Blueprint('main', __name__)


@main.route('/')
def index():
    return render_template('index.html')


@main.route('/profile')
@login_required
def profile():
    return render_template('profile.html', name=current_user.name)


app = create_app()

if __name__ == '__main__':
    db.create_all(app=create_app())
    app.run(debug=True)
```
This is the main entry point of the app.


The `models.py` file

```
from flask_login import UserMixin
from init import db


class User(UserMixin, db.Model):
    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(100), unique=True)
    password = db.Column(db.String(100))
    name = db.Column(db.String(1000))

    def __repr__(self):
        return'<User %r>' % self.id

    def __init__(self, email, password, name):
        db.create_all()
        self.email = email
        self.password = password
        self.name = name
```

After creating the logic for the app, we now create the templates of the different pages.

Create a templates folder in the main project folder and create a new html file called `base.html`

This is the main html file from which all the other  html file will inherit. We use **jinja templates** to extend the base.html to the other templates.

Here is the full `base.html`
```
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Flask Login</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.2/css/bulma.min.css" />
    <link rel="stylesheet" href="{{ url_for('static', filename='css/main.css') }}">

</head>
<body>
<section class="hero is-fullheight" style="background-image:#C4FCEF;">

    <div class="hero-head">
        <nav class="navbar">
            <div class="container">
                <div class="navbar-brand">
                    <a href="{{ url_for('main.index') }}" class="navbar-item" style="color:white">
                        CampNight
                    </a>
                </div>

                <div id="navbarMenuHeroA" class="navbar-menu">
                    <div class="navbar-end">
                        <a href="{{ url_for('main.index') }}" class="navbar-item">
                            Home
                        </a>
                        {% if current_user.is_authenticated %}
                        <a href="{{ url_for('main.profile') }}" class="navbar-item">
                            Profile
                        </a>
                        {% endif %}

                        {% if not current_user.is_authenticated %}
                        <a href="{{ url_for('auth.login') }}" class="navbar-item">
                            Login
                        </a>
                        <a href="{{ url_for('auth.signup') }}" class="navbar-item">
                            Sign Up
                        </a>
                        {% endif %}

                        {% if current_user.is_authenticated %}
                        <a href="{{ url_for('auth.logout') }}" class="navbar-item">
                            Logout
                        </a>
                        {% endif %}
                    </div>
                </div>
            </div>
        </nav>
    </div>

    <div class="hero-body">
        <div class="container has-text-centered">
            {% block content %}{% endblock %}
        </div>
    </div>
</section>
</body>
</html>
```
Notice that for the style we use **Bulma css** which is a nice framework. Read more about it [here](https://bulma.io/).

We then create an `index.html` which is the homepage. 

`index.html`
```
{% extends "base.html" %}

{%block content%}
<h1 class ="title">Welcome to CampNight </h1>
<h2 class="subtitle">Are you ready for an adventure?</h2>
{%endblock%}
```
Check out the jinja templates used here in curly brackets. You can read more about jinja templates [here](https://jinja.palletsprojects.com/en/3.0.x/).

We then create the `login.html` template

`login.html`
```
{% extends "base.html" %}

{%block content%}
<div class="column is-4 is-offset-4">
    <h3 class="title">Login</h3>
    <div class="box">
        {% with messages = get_flashed_messages() %}
            {% if messages %}
                <div class="notification is-danger">
                     {{ messages[0] }}
                 </div>
            {% endif %}
        {% endwith %}
        <form method="POST" action="/login">
            <div class="field">
                <div class="control">
                    <input class="input is-large" type="email" name="email" placeholder="Your Email" autofocus="">
                </div>
            </div>
            <div class="field">
                <div class="control">
                    <input class="input is-large" type="password" name="password" placeholder="Your Password">
                </div>
            </div>
            <div class="field">
                <label class="checkbox">
                    <input type="checkbox">
                    Remember me
                </label>
            </div>
            <button class="button is-block is-info is-large is-fullwidth">Login</button>
        </form>
    </div>
</div>
{%endblock%}
```
Then the `profile.html` to display the name of the particular user once they login.
```
{% extends 'base.html' %}

{% block content %}
<h1 class="title">
    Welcome, {{ name }}!
</h1>
{% endblock %}
```
We  then add the `signup.html`  for users to sign up.
```
{% extends "base.html" %}

{% block content %}
<div class="column is-4 is-offset-4">
    <h3 class="title">Sign Up</h3>
    <div class="box">
        {% with messages = get_flashed_messages() %}
            {% if messages %}
                <div class="notification is-danger">
                    {{ messages[0] }}<br> Go to <a href="{{ url_for('auth.login') }}">login page</a>
                </div>
            {% endif %}
        {% endwith %}
        <form method="POST" action="/signup">
            <div class="field">
                <div class="control">
                    <input class="input is-large" type="email" name="email" placeholder="Email" autofocus="">
                </div>
            </div>
            <div class="field">
                <div class="control">
                    <input class="input is-large" type="text" name="name" placeholder="Name" autofocus="">
                </div>
            </div>
            <div class="field">
                <div class="control">
                    <input class="input is-large" type="password" name="password" placeholder="Password">
                </div>
            </div>
            <button class="button is-block is-info is-large is-fullwidth">Sign Up</button>
        </form>
    </div>
</div>
{% endblock %}
```

Add another folder in the project folder and name it **static**.
This folder contains resources for the app such as customised css sheets and images added to the app.

The app is now finally ready and you can run it by running `python main.py` in the terminal. 

Run the app on local host 5000 and it will displayed in the browser.
![Sample webapp](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/udpn4kxrzhbj6trskz0s.png)

Feel free to run the app hosted on [here](https://campnight1.herokuapp.com/)


####Resources
Be sure to check out [this](https://medium.com/analytics-vidhya/creating-login-page-on-flask-9d20738d9f42) amazing medium article for more on how to implement user authentification in your web app using flask.