Here’s a step-by-step guide to implement Flask JWT Authentication with an example. Clone the flask-jwt authentication github repo and play around with the code
2. 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 ib
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.
3. CONTENTS
1. What are JSON Web Tokens?
2. What is Flask Framework?
3. Goal of Flask JWT Authentication Tutorial
4. Step-by-step Tutorial to Implement Flask
JWT Authentication
5. Conclusion
5. 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.
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.
6. Deserialized- This type is used when you’re
reading/writing information to the token. It
contains a payload and header.
8. 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.
12. Ubuntu 20.04 OS
Postman
Python 3.8+
Let’s start the implementation of the Flask JWT
Authentication. Here’s my system setup and
Flask JWT example for better understanding:
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.
13. 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.
sudo apt-get install python3-pip
Once you have the pip command installed on
your system, run the following command to
install virtualenv.
pip install virtualenv
Now, run the mkdir command to create a new
folder/directory for storing the virtual
environment.
mkdir myflaskproject
14. Change the current working directory to
myflaskproject:
cd myflaskproject
Inside the myflaskproject directory, create a
new virtual environment with the help of the
virtualenv tool:
virtualenv venv
After you have successfully created a virtual
environment using the irtualenv tool, activate
the virtual environment using the following
command:
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-
Install packages using pip
15. 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.
flask==1.1.2
pyjwt==2.0.0
datetime
uuid
Flask-SQLAlchemy
Now, use this file to install all the listed
packages with pip.
pip install -r requirements.txt
16. Set up a database
Users
Books
To keep this simple, we will use SQLite for this
project. Use the following code to install SQLite.
sudo apt-get update
sudo apt-get install sqlite3
Create a database named “bookstore” consisting
of two tables-
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.
17. Create the database:
sqlite3 bookstore.db
Run the below command for checking if you
have successfully created the database or not:
.databases
Create a new file named “app.py” in the
myflaskproject directory or run this command
in your terminal:
touch app.py
NOTE- while executing commands in the
terminal, make sure you do it inside the virtual
environment named “venv” we created earlier.
18. Now, paste the following code inside the python
file named app.py:
app.py
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
19. 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
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.
check_password_hash- For checking the
user’s password. It compares the password
provided by the user with the one stored in
the database.
⦿Packages from Flask framework
⦿Package from SQLAlchemy
⦿Package from werkzeug.security
20. 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.
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.
⦿datetime
⦿uuid
Now it’s time to configure settings for the
Bookstore API inside the app.py file using the
below code.
22. Now, we will create two models for the Books
and Users table.
app.py
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)
23. 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)
Moving ahead with Flask-JWT Authentication
Tutorial. Use the below code for creating tables
for both tables:
from app import db
db.create_all()
Generate Users and Books Tables
24. 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.
25. def token_required(f):
@wraps(f) :
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_i
d']).first()
except: return jsonify({'message': 'token is
invalid'})
return f(current_user, *args, **kwargs)
return decorator
26. 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.
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.
Creating routes for Users tables
27. Again, inside the app.py file, paste the following
code after token_required(f) function:
@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'})
28. 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:
29. @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).fir
st() 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.
30. @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})
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:
Creating routes for Books tables
31. @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:
33. 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.
@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}
34. 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.
@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}
35. Now run the app.py file by using the following
command inside the virtual environment in the
appropriate directory.
python app.py
If the above command does not work, here’s an
alternative command.
python3 app.py
You can find the entire source code here – Flask
JWT Authentication Example.
37. So, this was about how to implement Flask JWT
Authentication. I hope the purpose of landing
on this tutorial has been served the way you
expected. If you are interested in learning more
about Python, please visit Python Tutorials and
play around with the code. If you are looking for
assistance for token-based authentication with
Flask, then connect with us today to hire
Python developers from us to secure a Flask
REST API with JSON web token.