How to Implement JWT based Authentication in Python Flask?
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)