How to Implement JWT based Authentication in Python Flask?

ยท

3 min read

Authentication ensures that the users have access to the system. There are different kinds of auth systems in general. Here is a compilation of different Authentication methods and ideas behind it

The following blog is a part of 4 weeks Python to Project Bootcamp where Python beginners step up their Python skills and build their own projects

JWT based authentication

  • Works for mobile-based, web-based, and microservices-based auth
  • Relatively easy to implement

Let's start the implementation.

Install Flask-Jwt Library

pip install Flask-JWT

Initiallize JWT object

JWT needs a private key to decode the JWT token. Here it's super-secret. In production systems, we usually have this key in a.env` file. If a secret key of an application is exposed, anyone can start using the APIs generating API tokens.

Note: For the implementation of this blog, use the Python Flask Project template from here

# File:: app.py

app.config['SECRET_KEY'] = 'super-secret'
app.config['JWT_EXPIRATION_DELTA'] = timedelta(seconds=3000)

Create a User Model in models.py

# File:: models.py

class User(db.Model):
    username = db.Column(db.String(80),  primary_key=True, nullable=False)
    password = db.Column(db.String(120))

Write an authenticate function.

Flask-JWT uses two functions for auth purposes.

1. Authenticate

Logs in the user for the first time and returns the user object. Internally, JWT uses this object to create a JWT token.

2. Identity

The identity function is used on all protected APIs. Internally, flask-jwt decodes the JWT token, gets the user_id, and passes it to the identity function.

# File:: api.py

from flask_jwt import jwt_required, JWT, current_identity

def identity(payload):
    user_id = payload['identity']
    return User.query.filter_by(id=user_id).first()

def authenticate(username, password):
    user = User.query.filter_by(username=username).first()
    if user and user.password == password:
        return user

jwt = JWT(app, authenticate, identity)

Write Signup and Authenticated views

# File:: api.py

@app.route("/signup", methods=["POST"])
def signup():
    params = request.json()
    try:
        user = User(**params)
        db.session.add(user)
        db.session.commit()
    except IntegrityError:
        return {"Status": "Error", "result": "User already exists"}, 400
    return {"Status": "Success", "result": "User created"}

To authenticate your APIs, you need to add the decorator jwt_required to the view function.

@app.route("/hello")
@jwt_required()
def hello_world():
    return {"Status": "Success", "result": f"Hello {current_identity.username}"}

Let's Test Authentication

User Sign Up

Let's use /signup API to create the user

import requests
params = {
    "username": "joe",
    "password": "pass"
}

response = requests.post("/signup", json=params)
print (response.json())

User Login

/auth is an API that comes as default in the flask-jwt package. To log in, a user makes an API call with a username and password.

import requests
params = {
    "username": "joe",
    "password": "pass"
}

response = requests.post("/auth", json=params)
print (response.json())

Authenticating Future Requests

The above snippet will return a JSON response with a JWT Token. Future requests can use JWT Token for authentication.

headers = {
    "Authorization" : "JWT <token>"
}
requests.get("/hello", headers=headers)
ย