A simple JWT example with NodeJS and Python (part 1)
The following example is built using a Python Flask backend, a CURL-script to test it, and a simple React frontend that logs in, gets an authorization token and then continues to use it when accessing the backend.
We implement JWT using the Flask-JWT-Extended package.
pip install Flask-JWT-Extended
Backend in Python 3
import json from flask import Flask, request, jsonify from datetime import datetime, timedelta, timezone from flask_jwt_extended import create_access_token,get_jwt,get_jwt_identity, \ unset_jwt_cookies, jwt_required, JWTManager from flask_cors import CORS api = Flask(__name__) api.config["JWT_SECRET_KEY"] = "slemmig-torsk" api.config["JWT_ACCESS_TOKEN_EXPIRES"] = timedelta(seconds=300) # 5 minutes jwt = JWTManager(api) CORS(api)
refresh_expiring_jwts is called after each request, and will refresh expiring tokens
@api.after_request
def refresh_expiring_jwts(response):
try:
exp_timestamp = get_jwt()["exp"]
now = datetime.now(timezone.utc)
target_timestamp = datetime.timestamp(now + timedelta(minutes=30))
if target_timestamp > exp_timestamp:
access_token = create_access_token(identity=get_jwt_identity())
data = response.get_json()
if type(data) is dict:
data["access_token"] = access_token
response.data = json.dumps(data)
return response
except (RuntimeError, KeyError):
# Case where there is not a valid JWT. Just return the original respone
return response
This is the /login route which will respond with a token, or an error message
@api.route('/login', methods=["POST"])
@cross_origin()
def create_token():
# Really simple authorization for this demo!
email = request.json.get("email", None)
password = request.json.get("password", None)
if email != "test@test.se" or password != "123":
return {"msg": "Wrong email or password"}, 401
access_token = create_access_token(identity=email)
response = {"access_token":access_token}
return response
The logout route will just kill the token and make it unusable
@api.route("/logout", methods=["POST"])
@cross_origin()
def logout():
response = jsonify({"msg": "logout successful"})
unset_jwt_cookies(response)
return response
This is an example pf a protected route, which will deny access without a working token
@api.route('/protected')
@jwt_required()
@cross_origin()
def my_profile():
response_body = {
"endpointname": "protected",
"description" :"This endpoint is protected!"
}
return response_body
Run the application
if __name__ == "__main__": api.run(host="0.0.0.0")
You test the backend using this simple curl-script
curl -X POST http://[ip-address]:5000/login -H 'Content-Type: application/json' -d '{"email":"test@test.se","password":"123"}'
The response is something like this:
{"access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJmcmVzaCI6ZmFsc2UsImlhdCI6MTY1NDUxNDM3NiwianRpIjoiMmZjOTVlY2ItOGQyYS00MTYyLTk5OWMtZWRjOTIzMGI0YjczIiwidHlwZSI6ImFjY2VzcyIsInN1YiI6InRlc3RAdGVzdC5zZSIsIm5iZiI6MTY1NDUxNDM3NiwiZXhwIjoxNjU0NTE0Njc2fQ.7BtLHYKH6MgwfVP2wSUvFUAhNJwLDlMw14okHpYE31g"}
Copy the access_token and insert in the next statement:
curl http://192.168.1.67:5000/protected -X GET -H "Authorization: Bearer [access token here]"
Next article will show how to use this from a React application.
read part 2 of this series here: https://blogg.fsh.se/2022/06/08/a-simple-jwt-example-with-nodejs-and-python-part-2/
Github repository here: https://github.com/fshsweden/login-test-backend-python