In the Flask JWT Authentication tutorial, we will build a demo application together; learn about the Flask framework, REST APIs, and Auth Token Authentication. If this is your first time implementing token authentication in Flask, don’t worry! After going through this tutorial, your doubts would be solved and you won’t be a beginner anymore. For simplifying the tutorial, I have classified it into various sections.

Table of Contents

What are JSON Web Tokens?

JSON Web Tokens (JWT) is a secure and compact way to transmit data between two parties with the help of JSON objects.

JSON web token consists of three parts-

  • Payload
  • Header
  • Signature

JSON uses two different structure types for transmitting data.

  • Serialized- This type is used when you’re transferring information to the network via every request and response. It contains a payload, header, and signature.
  • Deserialized- This type is used when you’re reading/writing information to the token. It contains a payload and header.

What is Flask Framework?

Flask is a python based micro-framework used to build rest API. A “micro-framework” neither implies that your entire web app has to fit into a single Python code file nor Flask lacks functionality. The core idea of the Flask framework is to keep things simple but extensible. It allows developers to add custom extensions for database integration, authentication, session management, and all the other backend systems based on preferences.

Goal of Flask JWT Authentication Tutorial

Before knowing how to implement Flask JWT Authentication, let’s see the video and know what we will build.

Stop looking for Python developers because we are here!
Our developers are here to meet your requirements with their exceptional problem-solving skills and utter dedication. Contact us now and hire Python developer!

Step-by-step Tutorial to Implement Flask JWT Authentication

Let’s start the implementation of the Flask JWT Authentication. Here’s my system setup and JWT Flask Authentication example for better understanding:

  • Ubuntu 20.04 OS
  • Postman
  • Python 3.8+

Virtual environment Set Up using virtualenv

A virtual environment ensures that none of the packages used in the project conflict with system packages. It is also a good practice to avoid polluting your OS by installing every package directly onto the OS.

We will use the virtualenv command for setting up a new virtual environment in our project.

We will need pip command to proceed further. If you don’t have pip installed on your system, use the below command for installing pip on your system.

Copy Text
sudo apt-get install python3-pip

Once you have the pip command installed on your system, run the following command to install virtualenv.

Copy Text
pip install virtualenv

Now, run the mkdir command to create a new folder/directory for storing the virtual environment.

Copy Text
mkdir myflaskproject

Change the current working directory to myflaskproject:

Copy Text
cd myflaskproject

Inside the myflaskproject directory, create a new virtual environment with the help of the virtualenv tool:

Copy Text
virtualenv venv

After you have successfully created a virtual environment using the irtualenv tool, activate the virtual environment using the following command:

Install packages using pip

Now, it’s time to install the packages we need for this project to build Python REST API authentication token and other necessary packages for this API project such as-

  • flask
  • pyjwt
  • flask-sqlalchemy
  • datetime
  • uuid

An efficient way of doing this is by creating a requirements.txt file and listing all the packages into it. You can also declare the versions of the packages wherever necessary.

Copy Text
flask==1.1.2
pyjwt==2.0.0
datetime
uuid
Flask-SQLAlchemy

Now, use this file to install all the listed packages with pip.

Copy Text
pip install -r requirements.txt

Set up a database

To keep this simple, we will use SQLite for this project. Use the following code to install SQLite.

Copy Text
sudo apt-get update
sudo apt-get install sqlite3

Create a database named “bookstore” consisting of two tables-

  • Users
  • Books

Users table will store registered users. We will also keep a check, allowing only the registered users to access the Books table.

Books table will store the details and information about books, such as the book’s name, author of the book, publication of the book, and submitted by the registered users.

Create the database:

Copy Text
sqlite3 bookstore.db

Run the below command for checking if you have successfully created the database or not:

Copy Text
.databases

Create a new file named “app.py” in the myflaskproject directory or run this command in your terminal:

Copy Text
touch app.py

NOTE- while executing commands in the terminal, make sure you do it inside the virtual environment named “venv” we created earlier.

Now, paste the following code inside the python file named app.py:

app.py

Copy Text
from flask import Flask, jsonify, make_response, request
from werkzeug.security import generate_password_hash,check_password_hash
from flask_sqlalchemy import SQLAlchemy
from functools import wraps
import uuid
import jwt
import datetime

Let’s see the purpose of importing the packages mentioned above.

Packages from Flask framework

⦿ Packages from Flask framework

  • request – For keeping track of the associated data at the request level during a request.
  • jsonify – We will need jsonify to receive the output responses in JSON format and request

⦿ Package from SQLAlchemy

  • flask_sqlalchemy-This package will help us to integrate SQLAlchemy features into the Flask framework. SQLAlchemy is the Object Relational Mapper & Python SQL toolkit that provides full power and flexibility of SQL to developers.

⦿ Package from werkzeug.security

  • check_password_hash- For checking the user’s password. It compares the password provided by the user with the one stored in the database.

⦿ datetime– The package datetime will help us manipulate date and time as date objects. We need this module because python does not have any data type to support dates.

⦿ uuid– Universal Unique Identifiers create random ID numbers for users. The uuid is a very useful package, especially for such database engines that do not support incremental primary key features. Also, it is better to use multi-character alpha-numeric values as IDs instead of using linearly incremental numeric IDs.

Now it’s time to configure settings for the Bookstore API inside the app.py file using the below code.

app.py

Copy Text
app = Flask(__name__)
 
app.config['SECRET_KEY']='004f2af45d3a4e161a7dd2d17fdae47f'
app.config['SQLALCHEMY_DATABASE_URI']='sqlite://///home/manthantrivedi/Documents/Bacancy/bacancy_blogs/flask_auth/myflaskproject/bookstore.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
 
db = SQLAlchemy(app)

Here, the value assigned to the config variable ‘SECRET KEY’ can be auto-generated using a python library named ‘secrets.’ We can simply run the following code in your terminal to generate this value, as shown below.

configure settings for the Bookstore API

Now, we will create two models for the Books and Users table.

app.py

Copy Text
class Users(db.Model):
   id = db.Column(db.Integer, primary_key=True)
   public_id = db.Column(db.Integer)
   name = db.Column(db.String(50))
   password = db.Column(db.String(50))
   admin = db.Column(db.Boolean)
Copy Text
class Books(db.Model):
   id = db.Column(db.Integer, primary_key=True)
   user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
   name = db.Column(db.String(50), unique=True, nullable=False)
   Author = db.Column(db.String(50), unique=True, nullable=False)
   Publisher = db.Column(db.String(50), nullable=False)
   book_prize = db.Column(db.Integer)

Generate Users and Books Tables

Moving ahead with Flask-JWT Authentication Tutorial. Use the below code for creating tables for both tables:

Copy Text
from app import db
db.create_all()

Now, go to the app.py file and create the other functions required.

The “login_user” function will generate tokens to allow only registered users to access and manipulate a set of API operations against the Books table.

Simply paste the following code after the database model for both tables.

Copy Text
def token_required(f):
   @wraps(f)
   def decorator(*args, **kwargs):
       token = None
       if 'x-access-tokens' in request.headers:
           token = request.headers['x-access-tokens']
 
       if not token:
           return jsonify({'message': 'a valid token is missing'})
       try:
           data = jwt.decode(token, app.config['SECRET_KEY'], algorithms=["HS256"])
           current_user = Users.query.filter_by(public_id=data['public_id']).first()
       except:
           return jsonify({'message': 'token is invalid'})
 
       return f(current_user, *args, **kwargs)
   return decorator

This code is actually a special function. This function will create a custom decorator with the code required to create and validate tokens. Python provides a very amazing feature named function decorators. These function decorators allow very neat features for web development. In Flask, each view is considered as a function, and decorators are used for injecting additional functionality to one or more functions. In this case, the functionality handled by this custom decorator will be to create and validate tokens.

Creating routes for Users tables

In this step, we will generate a route for allowing users to register for the Books API using their name and password. With this route, we will create a view to encrypt the user’s password, store the new user’s details into the database, and return a success message.

Again, inside the app.py file, paste the following code after token_required(f) function:

Copy Text
@app.route('/register', methods=['POST'])
def signup_user(): 
   data = request.get_json() 
   hashed_password = generate_password_hash(data['password'], method='sha256')
 
   new_user = Users(public_id=str(uuid.uuid4()), name=data['name'], password=hashed_password, admin=False)
   db.session.add(new_user) 
   db.session.commit()   
   return jsonify({'message': 'registered successfully'})

Now, generate another route that will allow all the registered users to log in. With the login route, we will create a view to handle the user login feature. When a user logs in, the entered password is matched with the user’s stored password. If the password matches successfully, a random token is generated to access the Bookstore API. For instance, we will keep the expiration time for this random token to be 45 minutes.

You can simply update your file with the below-mentioned code beneath the registered route we created in the previous step:

Copy Text
@app.route('/login', methods=['POST']) 
def login_user():
   auth = request.authorization  
   if not auth or not auth.username or not auth.password: 
       return make_response('could not verify', 401, {'Authentication': 'login required"'})   
 
   user = Users.query.filter_by(name=auth.username).first()  
   if check_password_hash(user.password, auth.password):
       token = jwt.encode({'public_id' : user.public_id, 'exp' : datetime.datetime.utcnow() + datetime.timedelta(minutes=45)}, app.config['SECRET_KEY'], "HS256")
 
       return jsonify({'token' : token})
 
   return make_response('could not verify',  401, {'Authentication': '"login required"'})

Create another route in the app.py file to get all the registered users. This route verifies the registered users in the Users table and provides the output in JSON format. Use the below code after the login route.

Copy Text
@app.route('/users', methods=['GET'])
def get_all_users(): 
 
   users = Users.query.all()
   result = []  
   for user in users:  
       user_data = {}  
       user_data['public_id'] = user.public_id 
       user_data['name'] = user.name
       user_data['password'] = user.password
       user_data['admin'] = user.admin
     
       result.append(user_data)  
   return jsonify({'users': result})

Creating routes for Books tables

Let’s create routes for the Books table. These routes will allow users to retrieve all the Books in the database and delete them. We will also implement a mandatory check to verify the users having valid tokens can only perform any API requests.

Define a route for all the registered users to create a new book. The following code creates a route to meet this requirement:

Copy Text
@app.route('/book', methods=['POST'])
@token_required
def create_book(current_user):
 
   data = request.get_json()
 
   new_books = Books(name=data['name'], Author=data['Author'], Publisher=data['Publisher'], book_prize=data['book_prize'], user_id=current_user.id) 
   db.session.add(new_books)  
   db.session.commit() 
   return jsonify({'message' : 'new books created'})

Now, create a route to allow a logged in user with valid token to get all the books in the Books table as shown below:

Copy Text
@app.route('/books', methods=['GET'])
@token_required
def get_books(current_user):
 
   books = Books.query.filter_by(user_id=current_user.id).all()
   output = []
   for book in books:
       book_data = {}
       book_data['id'] = book.id
       book_data['name'] = book.name
       book_data['Author'] = book.Author
       book_data['Publisher'] = book.Publisher
       book_data['book_prize'] = book.book_prize
       output.append(book_data)
 
   return jsonify({'list_of_books' : output})

Finally, we will create the last route to delete a specific book. We will create a view responsible for handling requests made to delete an existing record in the Books table. It will verify and delete the given record from the DB, if exists. The below-mentioned code can be implemented after the route allows the user to retrieve a list of books.

Copy Text
@app.route('/books/<book_id>', methods=['DELETE'])
@token_required
def delete_book(current_user, book_id): 
 
   book = Books.query.filter_by(id=book_id, user_id=current_user.id).first()  
   if not book:  
       return jsonify({'message': 'book does not exist'})  
 
   db.session.delete(book) 
   db.session.commit()  
   return jsonify({'message': 'Book deleted'})
 
if  __name__ == '__main__': 
    app.run(debug=True)

Now run the app.py file by using the following command inside the virtual environment in the appropriate directory.

Copy Text
python app.py

If the above command does not work, here’s an alternative command.

Copy Text
python3 app.py

You can find the entire source code here – Python Flask JWT Authentication Example.

Conclusion

So, this was about how to implement Flask JWT Authentication. I hope the purpose of landing on this flask token authentication tutorial has been served the way you expected. We are here to help you with your queries. Write us back if you have any questions, suggestions, or feedback.

Frequently Asked Questions (FAQs)

Some of the advantages of using Flask are-
– Provides an inbuilt development server
– Higher compatibility with modern technologies
– Routing URL is simple
– Minimal and powerful framework
– Smaller codebase size

Use Python’s package manager, pip, to install flask on your Linux system-

pip install Flask

Flask is defined as a Microframework because it only offers the primary features like – request, blueprints, and routing. We can use Flask-Extension for using features like ORM, Caching, forms, and so on.

Python Tutorials

Explore Advanced knowledge of Programming

LEARN NOW

Build Your Agile Team

Hire Skilled Developer From Us

[email protected]

Your Success Is Guaranteed !

We accelerate the release of digital product and guaranteed their success

We Use Slack, Jira & GitHub for Accurate Deployment and Effective Communication.

How Can We Help You?