### Install Flask-JWT-Extended from Source Source: https://github.com/vimalloc/flask-jwt-extended/blob/main/docs/installation.md Clone the repository and run setup.py install to install the library directly from the source code. ```bash $ python setup.py install ``` -------------------------------- ### Complete Flask App with User Loading Source: https://github.com/vimalloc/flask-jwt-extended/blob/main/docs/automatic_user_loading.md This example demonstrates a full Flask application setup with SQLAlchemy for user management, JWT authentication, and automatic user loading using `user_identity_loader` and `user_lookup_loader`. ```python from hmac import compare_digest from flask import Flask from flask import jsonify from flask import request from flask_sqlalchemy import SQLAlchemy from flask_jwt_extended import create_access_token from flask_jwt_extended import current_user from flask_jwt_extended import jwt_required from flask_jwt_extended import JWTManager app = Flask(__name__) app.config["JWT_SECRET_KEY"] = "super-secret" # Change this! app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite://" app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False jwt = JWTManager(app) db = SQLAlchemy(app) class User(db.Model): id = db.Column(db.Integer, primary_key=True) username = db.Column(db.Text, nullable=False, unique=True) full_name = db.Column(db.Text, nullable=False) # NOTE: In a real application make sure to properly hash and salt passwords def check_password(self, password): return compare_digest(password, "password") # Register a callback function that takes whatever object is passed in as the # identity when creating JWTs and converts it to a JSON serializable format. @jwt.user_identity_loader def user_identity_lookup(user): return user.id # Register a callback function that loads a user from your database whenever # a protected route is accessed. This should return any python object on a # successful lookup, or None if the lookup failed for any reason (for example # if the user has been deleted from the database). @jwt.user_lookup_loader def user_lookup_callback(_jwt_header, jwt_data): identity = jwt_data["sub"] return User.query.filter_by(id=identity).one_or_none() @app.route("/login", methods=["POST"]) def login(): username = request.json.get("username", None) password = request.json.get("password", None) user = User.query.filter_by(username=username).one_or_none() if not user or not user.check_password(password): return jsonify("Wrong username or password"), 401 # Notice that we are passing in the actual sqlalchemy user object here access_token = create_access_token(identity=user) return jsonify(access_token=access_token) @app.route("/who_am_i", methods=["GET"]) @jwt_required() def protected(): # We can now access our sqlalchemy User object via `current_user`. return jsonify( id=current_user.id, full_name=current_user.full_name, username=current_user.username, ) if __name__ == "__main__": db.create_all() db.session.add(User(full_name="Bruce Wayne", username="batman")) db.session.add(User(full_name="Ann Takamaki", username="panther")) db.session.add(User(full_name="Jester Lavore", username="little_sapphire")) db.session.commit() app.run() ``` -------------------------------- ### Install Development Requirements Source: https://github.com/vimalloc/flask-jwt-extended/blob/main/README.md Install necessary packages for development and set up git hooks for linting and formatting. ```bash pip install -r requirements.txt pre-commit install ``` -------------------------------- ### Install Flask-JWT-Extended with Asymmetric Crypto Support Source: https://github.com/vimalloc/flask-jwt-extended/blob/main/docs/installation.md Install Flask-JWT-Extended with the 'asymmetric_crypto' extra to enable asymmetric key signing algorithms. ```bash $ pip install flask-jwt-extended[asymmetric_crypto] ``` -------------------------------- ### Install Flask-JWT-Extended with Pip Source: https://github.com/vimalloc/flask-jwt-extended/blob/main/docs/installation.md Use this command to install the basic Flask-JWT-Extended package. ```bash $ pip install flask-jwt-extended ``` -------------------------------- ### Install Flask-JWT-Extended Source: https://context7.com/vimalloc/flask-jwt-extended/llms.txt Install Flask-JWT-Extended via pip. Include the `asymmetric_crypto` extra for RSA/EC key signing support. ```bash pip install flask-jwt-extended # For asymmetric (RS256/ES256) algorithm support: pip install flask-jwt-extended[asymmetric_crypto] ``` -------------------------------- ### Token Freshness Pattern Setup Source: https://github.com/vimalloc/flask-jwt-extended/blob/main/docs/refreshing_tokens.md Initializes Flask app and JWTManager with configuration for access and refresh token expiration times. This setup is foundational for implementing the token freshness pattern. ```python from datetime import timedelta from flask import Flask from flask import jsonify from flask import request from flask_jwt_extended import create_access_token from flask_jwt_extended import create_refresh_token from flask_jwt_extended import get_jwt_identity from flask_jwt_extended import jwt_required from flask_jwt_extended import JWTManager app = Flask(__name__) app.config["JWT_SECRET_KEY"] = "super-secret" # Change this! app.config["JWT_ACCESS_TOKEN_EXPIRES"] = timedelta(hours=1) app.config["JWT_REFRESH_TOKEN_EXPIRES"] = timedelta(days=30) jwt = JWTManager(app) ``` -------------------------------- ### HTTPie Login Request Source: https://github.com/vimalloc/flask-jwt-extended/blob/main/docs/automatic_user_loading.md Example of how to log in a user and obtain an access token using HTTPie. ```bash $ http POST :5000/login username=panther password=password HTTP/1.0 200 OK Content-Length: 281 Content-Type: application/json Date: Sun, 24 Jan 2021 17:23:31 GMT Server: Werkzeug/1.0.1 Python/3.8.6 { "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJmcmVzaCI6ZmFsc2UsImlhdCI6MTYxMTUwOTAxMSwianRpIjoiNGFmN2ViNTAtMjk3Yy00ZmY4LWJmOTYtMTZlMDE5MWEzYzMwIiwibmJmIjoxNjExNTA5MDExLCJ0eXBlIjoiYWNjZXNzIiwic3ViIjoyLCJleHAiOjE2MTQxMDEwMTF9.2UhZo-xo19NXaqKLwcMz0NBLAcxxEUeK4Ziqk1T_9h0" } ``` -------------------------------- ### Basic Flask JWT Authentication Setup Source: https://github.com/vimalloc/flask-jwt-extended/blob/main/docs/basic_usage.md Set up a Flask application with Flask-JWT-Extended, configure a secret key, and define login and protected routes. ```python from flask import Flask from flask import jsonify from flask import request from flask_jwt_extended import create_access_token from flask_jwt_extended import get_jwt_identity from flask_jwt_extended import jwt_required from flask_jwt_extended import JWTManager app = Flask(__name__) # Setup the Flask-JWT-Extended extension app.config["JWT_SECRET_KEY"] = "super-secret" # Change this! jwt = JWTManager(app) # Create a route to authenticate your users and return JWTs. The # create_access_token() function is used to actually generate the JWT. @app.route("/login", methods=["POST"]) def login(): username = request.json.get("username", None) password = request.json.get("password", None) if username != "test" or password != "test": return jsonify({"msg": "Bad username or password"}), 401 access_token = create_access_token(identity=username) return jsonify(access_token=access_token) # Protect a route with jwt_required, which will kick out requests # without a valid JWT present. @app.route("/protected", methods=["GET"]) @jwt_required() def protected(): # Access the identity of the current user with get_jwt_identity current_user = get_jwt_identity() return jsonify(logged_in_as=current_user), 200 if __name__ == "__main__": app.run() ``` -------------------------------- ### Making a Request with a Refresh Token (HTTPie) Source: https://github.com/vimalloc/flask-jwt-extended/blob/main/docs/refreshing_tokens.md Example of how to make a POST request to the refresh endpoint using HTTPie, including the Authorization header with a bearer token. ```bash $ http POST :5000/refresh Authorization:"Bearer $REFRESH_TOKEN" ``` -------------------------------- ### Flask-JWT-Extended Asymmetric Signing Configuration Source: https://context7.com/vimalloc/flask-jwt-extended/llms.txt Configure settings for asymmetric algorithms like RS256 or ES256. Requires installing flask-jwt-extended[asymmetric_crypto]. ```python # --- Asymmetric Signing (RS256 / ES256) --- # pip install flask-jwt-extended[asymmetric_crypto] app.config["JWT_ALGORITHM"] = "RS256" app.config["JWT_PRIVATE_KEY"] = open("private.pem").read() # For encoding app.config["JWT_PUBLIC_KEY"] = open("public.pem").read() # For decoding ``` -------------------------------- ### Protected Route Example Source: https://github.com/vimalloc/flask-jwt-extended/blob/main/docs/refreshing_tokens.md A standard protected route that requires a valid access token to access. ```python @app.route("/protected", methods=["GET"]) @jwt_required() def protected(): return jsonify(foo="bar") if __name__ == "__main__": app.run() ``` -------------------------------- ### Install Flask-JWT-Extended with Escaped Brackets for ZSH Source: https://github.com/vimalloc/flask-jwt-extended/blob/main/docs/installation.md If using ZSH or similar shells, you may need to escape the brackets when installing with extras. ```bash $ pip install flask-jwt-extended\[asymmetric_crypto\] ``` -------------------------------- ### Revoking Access and Refresh Tokens (Database) Source: https://github.com/vimalloc/flask-jwt-extended/blob/main/docs/blocklist_and_token_revoking.md This example shows a more comprehensive approach to revoking tokens, handling both access and refresh tokens and storing their type in the blocklist. ```APIDOC ## DELETE /logout ### Description Revokes the current user's access or refresh token by adding its JTI and type to the blocklist. ### Method DELETE ### Endpoint /logout ### Parameters #### Headers - **Authorization** (string) - Required - Bearer token for authentication. `verify_type=False` allows revoking both access and refresh tokens. ### Request Body * **refresh_token** (string) - Optional - The refresh token to revoke, sent in the request body. ### Response #### Success Response (200) - **msg** (string) - Confirmation message indicating whether an access or refresh token was revoked. #### Response Example ```json { "msg": "Access token successfully revoked" } ``` ``` -------------------------------- ### HTTPie Protected Route Request Source: https://github.com/vimalloc/flask-jwt-extended/blob/main/docs/automatic_user_loading.md Example of how to access a protected route using an obtained JWT access token with HTTPie. ```bash $ export JWT="eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJmcmVzaCI6ZmFsc2UsImlhdCI6MTYxMTUwOTAxMSwianRpIjoiNGFmN2ViNTAtMjk3Yy00ZmY4LWJmOTYtMTZlMDE5MWEzYzMwIiwibmJmIjoxNjExNTA5MDExLCJ0eXBlIjoiYWNjZXNzIiwic3ViIjoyLCJleHAiOjE2MTQxMDEwMTF9.2UhZo-xo19NXaqKLwcMz0NBLAcxxEUeK4Ziqk1T_9h0" $ http GET :5000/who_am_i Authorization:"Bearer $JWT" HTTP/1.0 200 OK Content-Length: 57 Content-Type: application/json Date: Sun, 24 Jan 2021 17:31:34 GMT Server: Werkzeug/1.0.1 Python/3.8.6 { "id": 2, "full_name": "Ann Takamaki", "username": "panther" } ``` -------------------------------- ### Protected Endpoint Source: https://github.com/vimalloc/flask-jwt-extended/blob/main/docs/refreshing_tokens.md An example of a protected route that requires a fresh access token for access. ```APIDOC ## GET /protected ### Description This endpoint is protected and can only be accessed with a fresh access token. It demonstrates how to enforce freshness for specific routes. ### Method GET ### Endpoint /protected ### Parameters (No explicit parameters are defined in the source, but a valid, fresh JWT is required via the JWT authentication mechanism). ### Response #### Success Response (200) - **foo** (string) - Example response data. #### Response Example ```json { "foo": "bar" } ``` ``` -------------------------------- ### Configure JWT Token Location (Query String) Source: https://context7.com/vimalloc/flask-jwt-extended/llms.txt Configure the JWT token to be expected in the query string. This example sets the query string parameter name to 'jwt'. ```python app.config["JWT_QUERY_STRING_NAME"] = "jwt" # ?jwt= ``` -------------------------------- ### Making Requests with JWT using HTTPie Source: https://github.com/vimalloc/flask-jwt-extended/blob/main/docs/basic_usage.md Demonstrates how to interact with the Flask application using HTTPie, including making a request without a token, logging in to get a token, and accessing a protected route with the token. ```bash $ http GET :5000/protected HTTP/1.0 401 UNAUTHORIZED Content-Length: 39 Content-Type: application/json Date: Sun, 24 Jan 2021 18:09:17 GMT Server: Werkzeug/1.0.1 Python/3.8.6 { "msg": "Missing Authorization Header" } $ http POST :5000/login username=test password=test HTTP/1.0 200 OK Content-Length: 288 Content-Type: application/json Date: Sun, 24 Jan 2021 18:10:39 GMT Server: Werkzeug/1.0.1 Python/3.8.6 { "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJmcmVzaCI6ZmFsc2UsImlhdCI6MTYxMTUxMTgzOSwianRpIjoiMmI0NzliNTQtYTI0OS00ZDNjLWE4NjItZGVkZGIzODljNmVlIiwibmJmIjoxNjExNTExODM5LCJ0eXBlIjoiYWNjZXNzIiwic3ViIjoidGVzdCIsImV4cCI6MTYxNDEwMzgzOX0.UpTueBRwNLK8e-06-oo5Y_9eWbaN5T3IHwKsy6Jauaw" } $ export JWT="eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJmcmVzaCI6ZmFsc2UsImlhdCI6MTYxMTUxMTgzOSwianRpIjoiMmI0NzliNTQtYTI0OS00ZDNjLWE4NjItZGVkZGIzODljNmVlIiwibmJmIjoxNjExNTExODM5LCJ0eXBlIjoiYWNjZXNzIiwic3ViIjoidGVzdCIsImV4cCI6MTYxNDEwMzgzOX0.UpTueBRwNLK8e-06-oo5Y_9eWbaN5T3IHwKsy6Jauaw" $ http GET :5000/protected Authorization:"Bearer $JWT" HTTP/1.0 200 OK Content-Length: 24 Content-Type: application/json Date: Sun, 24 Jan 2021 18:12:02 GMT Server: Werkzeug/1.0.1 Python/3.8.6 { "logged_in_as": "test" } ``` -------------------------------- ### Database Blocklist Implementation Source: https://github.com/vimalloc/flask-jwt-extended/blob/main/docs/blocklist_and_token_revoking.md Use this example with SQLAlchemy to store revoked JWTs in a database. This approach allows for storing metadata about revoked tokens, such as revocation time and reason. ```python from datetime import datetime from datetime import timedelta from datetime import timezone from flask import Flask from flask import jsonify from flask_sqlalchemy import SQLAlchemy from flask_jwt_extended import create_access_token from flask_jwt_extended import get_jwt from flask_jwt_extended import jwt_required from flask_jwt_extended import JWTManager app = Flask(__name__) ACCESS_EXPIRES = timedelta(hours=1) app.config["JWT_SECRET_KEY"] = "super-secret" # Change this! app.config["JWT_ACCESS_TOKEN_EXPIRES"] = ACCESS_EXPIRES jwt = JWTManager(app) # We are using an in memory database here as an example. Make sure to use a # database with persistent storage in production! app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite://" app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False db = SQLAlchemy(app) # This could be expanded to fit the needs of your application. For example, # it could track who revoked a JWT, when a token expires, notes for why a # JWT was revoked, an endpoint to un-revoked a JWT, etc. # Making jti an index can significantly speed up the search when there are ``` -------------------------------- ### Revoking Access Tokens (Database) Source: https://github.com/vimalloc/flask-jwt-extended/blob/main/docs/blocklist_and_token_revoking.md This example demonstrates how to revoke the current user's access token by saving its unique identifier (jti) into a database table. ```APIDOC ## POST /login ### Description Creates an access token for a user. ### Method POST ### Endpoint /login ### Request Example ```json { "example": "No request body" } ``` ### Response #### Success Response (200) - **access_token** (string) - The generated access token. #### Response Example ```json { "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmcmVzaCI6ZmFsc2UsImlhdCI6MTcwNzQ2NzQ2MCwianRpIjoiYjQ1YjY5YjMtYjQ2MC00YjQ0LWE0YjEtYjQzYjQyY2Q1YjY4IiwidHlwZSI6ImFjY2VzcyIsInN1YiI6ImV4YW1wbGVfdXNlciIsIm5iZiI6MTcwNzQ2NzQ2MCwiZXhwIjoxNzA3NDY4MzYwfQ.example_signature" } ``` ## DELETE /logout ### Description Revokes the current user's access token by adding its JTI to the blocklist. ### Method DELETE ### Endpoint /logout ### Parameters #### Headers - **Authorization** (string) - Required - Bearer token for authentication. ### Response #### Success Response (200) - **msg** (string) - Confirmation message that the JWT was revoked. #### Response Example ```json { "msg": "JWT revoked" } ``` ## GET /protected ### Description An example endpoint that requires a valid JWT for access. ### Method GET ### Endpoint /protected ### Parameters #### Headers - **Authorization** (string) - Required - Bearer token for authentication. ### Response #### Success Response (200) - **hello** (string) - A simple greeting. #### Response Example ```json { "hello": "world" } ``` ``` -------------------------------- ### Protected Endpoint Source: https://github.com/vimalloc/flask-jwt-extended/blob/main/docs/blocklist_and_token_revoking.md An example of a protected endpoint that requires a valid JWT to access. ```python @app.route("/protected", methods=["GET"]) @jwt_required() def protected(): return jsonify(hello="world") ``` -------------------------------- ### Redis Blocklist Implementation Source: https://github.com/vimalloc/flask-jwt-extended/blob/main/docs/blocklist_and_token_revoking.md Use this example to store revoked JWTs in Redis. Ensure Redis is configured for persistence in production. The Time To Live (TTL) feature automatically clears expired tokens. ```python from datetime import timedelta import redis from flask import Flask from flask import jsonify from flask_jwt_extended import create_access_token from flask_jwt_extended import get_jwt from flask_jwt_extended import jwt_required from flask_jwt_extended import JWTManager ACCESS_EXPIRES = timedelta(hours=1) app = Flask(__name__) app.config["JWT_SECRET_KEY"] = "super-secret" # Change this! app.config["JWT_ACCESS_TOKEN_EXPIRES"] = ACCESS_EXPIRES jwt = JWTManager(app) # Setup our redis connection for storing the blocklisted tokens. You will probably # want your redis instance configured to persist data to disk, so that a restart # does not cause your application to forget that a JWT was revoked. jwt_redis_blocklist = redis.StrictRedis( host="localhost", port=6379, db=0, decode_responses=True ) # Callback function to check if a JWT exists in the redis blocklist @jwt.token_in_blocklist_loader def check_if_token_is_revoked(jwt_header, jwt_payload: dict): jti = jwt_payload["jti"] token_in_redis = jwt_redis_blocklist.get(jti) return token_in_redis is not None @app.route("/login", methods=["POST"]) def login(): access_token = create_access_token(identity="example_user") return jsonify(access_token=access_token) # Endpoint for revoking the current users access token. Save the JWTs unique # identifier (jti) in redis. Also set a Time to Live (TTL) when storing the JWT # so that it will automatically be cleared out of redis after the token expires. @app.route("/logout", methods=["DELETE"]) @jwt_required() def logout(): jti = get_jwt()["jti"] jwt_redis_blocklist.set(jti, "", ex=ACCESS_EXPIRES) return jsonify(msg="Access token revoked") # A blocklisted access token will not be able to access this any more @app.route("/protected", methods=["GET"]) @jwt_required() def protected(): return jsonify(hello="world") if __name__ == "__main__": app.run() ``` -------------------------------- ### Get All JWT Claims with get_jwt Source: https://context7.com/vimalloc/flask-jwt-extended/llms.txt Access the complete decoded JWT payload, including standard claims like 'sub', 'exp', 'iat', 'jti', 'type', 'fresh', and any custom claims. ```python from flask import Flask, jsonify, request from flask_jwt_extended import JWTManager, create_access_token, jwt_required, get_jwt app = Flask(__name__) app.config["JWT_SECRET_KEY"] = "super-secret" jwt = JWTManager(app) @app.route("/login", methods=["POST"]) def login(): token = create_access_token( identity="alice", additional_claims={"role": "editor", "tenant": "acme"}, ) return jsonify(access_token=token) @app.route("/claims") @jwt_required() def claims(): jwt_data = get_jwt() return jsonify( identity=jwt_data["sub"], role=jwt_data.get("role"), tenant=jwt_data.get("tenant"), jti=jwt_data["jti"], # unique identifier (useful for blocklisting) is_fresh=jwt_data["fresh"], token_type=jwt_data["type"], ) ``` -------------------------------- ### get_jwt — Get All JWT Claims Source: https://context7.com/vimalloc/flask-jwt-extended/llms.txt Returns the full decoded JWT payload dictionary, including standard claims (`sub`, `exp`, `iat`, `jti`, `type`, `fresh`) and any additional custom claims. ```APIDOC ## get_jwt — Get All JWT Claims Returns the full decoded JWT payload dictionary, including standard claims (`sub`, `exp`, `iat`, `jti`, `type`, `fresh`) and any additional custom claims. ### Usage Example: ```python from flask import Flask, jsonify, request from flask_jwt_extended import JWTManager, create_access_token, jwt_required, get_jwt app = Flask(__name__) app.config["JWT_SECRET_KEY"] = "super-secret" jwt = JWTManager(app) @app.route("/login", methods=["POST"]) def login(): token = create_access_token( identity="alice", additional_claims={"role": "editor", "tenant": "acme"}, ) return jsonify(access_token=token) @app.route("/claims") @jwt_required() def claims(): jwt_data = get_jwt() return jsonify( identity=jwt_data["sub"], role=jwt_data.get("role"), tenant=jwt_data.get("tenant"), jti=jwt_data["jti"], # unique identifier (useful for blocklisting) is_fresh=jwt_data["fresh"], token_type=jwt_data["type"], ) ``` ### Response Example: ```json { "identity": "alice", "role": "editor", "tenant": "acme", "jti": "some-unique-id", "is_fresh": false, "token_type": "access" } ``` ``` -------------------------------- ### Implement Token Revocation with @jwt.token_in_blocklist_loader Source: https://context7.com/vimalloc/flask-jwt-extended/llms.txt Register a callback using `@jwt.token_in_blocklist_loader` to check if a JWT has been revoked on every protected request. Return `True` to block the token and `False` to allow it. This example uses Redis to store revoked tokens. ```python import redis from datetime import timedelta from flask import Flask, jsonify from flask_jwt_extended import JWTManager, create_access_token, get_jwt, jwt_required ACCESS_EXPIRES = timedelta(hours=1) app = Flask(__name__) app.config["JWT_SECRET_KEY"] = "super-secret" app.config["JWT_ACCESS_TOKEN_EXPIRES"] = ACCESS_EXPIRES jwt = JWTManager(app) jwt_redis_blocklist = redis.StrictRedis(host="localhost", port=6379, db=0, decode_responses=True) @jwt.token_in_blocklist_loader def check_if_token_is_revoked(jwt_header, jwt_payload: dict): jti = jwt_payload["jti"] return jwt_redis_blocklist.get(jti) is not None # True = revoked @app.route("/login", methods=["POST"]) def login(): return jsonify(access_token=create_access_token(identity="alice")) @app.route("/logout", methods=["DELETE"]) @jwt_required() def logout(): jti = get_jwt()["jti"] jwt_redis_blocklist.set(jti, "", ex=ACCESS_EXPIRES) # TTL matches token expiry return jsonify(msg="Access token revoked") @app.route("/protected") @jwt_required() def protected(): return jsonify(hello="world") # After /logout, the same token will receive: 401 {"msg": "Token has been revoked"} ``` -------------------------------- ### Generate Local Documentation Source: https://github.com/vimalloc/flask-jwt-extended/blob/main/README.md Clean previous builds, generate HTML documentation, and open the index file. ```bash make clean && make html && open _build/html/index.html ``` -------------------------------- ### Create Access Token with Timed Freshness Source: https://github.com/vimalloc/flask-jwt-extended/blob/main/docs/refreshing_tokens.md Demonstrates how to create an access token that is considered fresh for a specific duration using `datetime.timedelta`. ```python import datetime # Assuming create_access_token is imported # access_token = create_access_token(identity, fresh=datetime.timedelta(minutes=15)) ``` -------------------------------- ### Login Route: Create Access and Refresh Tokens Source: https://github.com/vimalloc/flask-jwt-extended/blob/main/docs/refreshing_tokens.md This route handles user login, verifies credentials, and returns both a fresh access token and a refresh token upon successful authentication. ```python from flask import request, jsonify from flask_jwt_extended import create_access_token, jwt_required, JWTManager, create_refresh_token, get_jwt_identity # Assuming app and JWTManager are initialized elsewhere # app = Flask(__name__) # app.config["JWT_SECRET_KEY"] = "super-secret" # Change this in production! # jwt = JWTManager(app) @app.route("/login", methods=["POST"]) def login(): username = request.json.get("username", None) password = request.json.get("password", None) if username != "test" or password != "test": return jsonify({"msg": "Bad username or password"}), 401 access_token = create_access_token(identity="example_user", fresh=True) refresh_token = create_refresh_token(identity="example_user") return jsonify(access_token=access_token, refresh_token=refresh_token) ``` -------------------------------- ### Set Flask Configuration Option Source: https://github.com/vimalloc/flask-jwt-extended/blob/main/docs/options.md Demonstrates the standard method for setting configuration options in Flask applications. ```python app.config["OPTION_NAME"] = option_value ``` -------------------------------- ### Create Access Tokens with Options Source: https://context7.com/vimalloc/flask-jwt-extended/llms.txt Create signed access tokens for a given identity. Supports basic tokens, fresh tokens, tokens with custom claims and headers, and tokens that never expire (use with caution). ```python from datetime import timedelta from flask import Flask, jsonify, request from flask_jwt_extended import JWTManager, create_access_token app = Flask(__name__) app.config["JWT_SECRET_KEY"] = "super-secret" jwt = JWTManager(app) @app.route("/login", methods=["POST"]) def login(): username = request.json.get("username") password = request.json.get("password") if username != "test" or password != "test": return jsonify({"msg": "Bad username or password"}), 401 # Basic token access_token = create_access_token(identity=username) # Fresh token (for sensitive operations), expires in 1 hour fresh_token = create_access_token( identity=username, fresh=True, expires_delta=timedelta(hours=1), ) # Token with additional claims merged in token_with_claims = create_access_token( identity=username, additional_claims={"role": "admin", "aud": "my-app"}, additional_headers={"kid": "key-id-1"}, ) # Token that never expires (DANGEROUS – avoid in production) no_expire_token = create_access_token(identity=username, expires_delta=False) return jsonify( access_token=access_token, fresh_token=fresh_token, token_with_claims=token_with_claims, ) ``` -------------------------------- ### Run All Tests with Tox Source: https://github.com/vimalloc/flask-jwt-extended/blob/main/README.md Execute all tests, including unit tests, type checking, coverage, documentation builds, and style checks, using Tox. ```bash tox ``` -------------------------------- ### Login Endpoint Source: https://github.com/vimalloc/flask-jwt-extended/blob/main/docs/blocklist_and_token_revoking.md A simple endpoint to create and return an access token for a user. ```python @app.route("/login", methods=["POST"]) def login(): access_token = create_access_token(identity="example_user") return jsonify(access_token=access_token) ``` -------------------------------- ### Get JWT Subject with get_jwt_identity Source: https://context7.com/vimalloc/flask-jwt-extended/llms.txt Retrieve the 'sub' claim (identity) from the JWT in the current request context. Returns None for optionally protected endpoints when no JWT is present. ```python from flask import Flask, jsonify from flask_jwt_extended import JWTManager, create_access_token, jwt_required, get_jwt_identity app = Flask(__name__) app.config["JWT_SECRET_KEY"] = "super-secret" jwt = JWTManager(app) @app.route("/login", methods=["POST"]) def login(): return jsonify(access_token=create_access_token(identity="user-42")) @app.route("/whoami") @jwt_required() def whoami(): identity = get_jwt_identity() # returns "user-42" return jsonify(identity=identity) ``` -------------------------------- ### Login Endpoint Source: https://github.com/vimalloc/flask-jwt-extended/blob/main/docs/refreshing_tokens.md Handles user login by verifying credentials and returning access and refresh tokens. ```APIDOC ## POST /login ### Description Authenticates a user based on username and password. If successful, it returns both an access token and a refresh token. The access token is marked as fresh. ### Method POST ### Endpoint /login ### Parameters #### Request Body - **username** (string) - Required - The username for authentication. - **password** (string) - Required - The password for authentication. ### Request Example ```json { "username": "test", "password": "test" } ``` ### Response #### Success Response (200) - **access_token** (string) - The generated access token. - **refresh_token** (string) - The generated refresh token. #### Response Example ```json { "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." } ``` #### Error Response (401) - **msg** (string) - Bad username or password ``` -------------------------------- ### Handling Revoked Tokens with New Callback Signature Source: https://github.com/vimalloc/flask-jwt-extended/blob/main/docs/v4_upgrade_guide.md The `revoked_token_loader` callback now expects two arguments: `jwt_header` and `jwt_payload`. This example demonstrates how to access the payload to customize the response message. ```python from flask import jsonify @jwt.revoked_token_loader def revoked_token_response(jwt_header, jwt_payload): return jsonify(msg=f"I'm sorry {jwt_payload['sub']} I can't let you do that") ``` -------------------------------- ### Create Refresh Tokens and New Access Tokens Source: https://context7.com/vimalloc/flask-jwt-extended/llms.txt Generate long-lived refresh tokens to mint new access tokens. The `/refresh` endpoint requires a refresh token and can create a new, non-fresh access token. ```python from datetime import timedelta from flask import Flask, jsonify from flask_jwt_extended import ( JWTManager, create_access_token, create_refresh_token, get_jwt_identity, jwt_required, ) app = Flask(__name__) app.config["JWT_SECRET_KEY"] = "super-secret" app.config["JWT_ACCESS_TOKEN_EXPIRES"] = timedelta(hours=1) app.config["JWT_REFRESH_TOKEN_EXPIRES"] = timedelta(days=30) jwt = JWTManager(app) @app.route("/login", methods=["POST"]) def login(): access_token = create_access_token(identity="example_user") refresh_token = create_refresh_token(identity="example_user") return jsonify(access_token=access_token, refresh_token=refresh_token) # Only refresh tokens are accepted here (refresh=True) @app.route("/refresh", methods=["POST"]) @jwt_required(refresh=True) def refresh(): identity = get_jwt_identity() new_access_token = create_access_token(identity=identity, fresh=False) return jsonify(access_token=new_access_token) # $ http POST :5000/login username=test password=test # → {"access_token": "eyJ...", "refresh_token": "eyJ..."} # $ http POST :5000/refresh Authorization:"Bearer " # → {"access_token": "eyJ..."} ``` -------------------------------- ### get_jwt_identity — Get the JWT Subject Source: https://context7.com/vimalloc/flask-jwt-extended/llms.txt Returns the `sub` claim (identity) of the JWT in the current request context. Returns `None` in optionally protected endpoints when no JWT is present. ```APIDOC ## get_jwt_identity — Get the JWT Subject Returns the `sub` claim (identity) of the JWT in the current request context. Returns `None` in optionally protected endpoints when no JWT is present. ### Usage Example: ```python from flask import Flask, jsonify from flask_jwt_extended import JWTManager, create_access_token, jwt_required, get_jwt_identity app = Flask(__name__) app.config["JWT_SECRET_KEY"] = "super-secret" jwt = JWTManager(app) @app.route("/login", methods=["POST"]) def login(): return jsonify(access_token=create_access_token(identity="user-42")) @app.route("/whoami") @jwt_required() def whoami(): identity = get_jwt_identity() # returns "user-42" return jsonify(identity=identity) ``` ### Request Example: ```bash $ http GET :5000/whoami Authorization:"Bearer " ``` ### Response Example: ```json { "identity": "user-42" } ``` ``` -------------------------------- ### Get Current User Object Function Source: https://context7.com/vimalloc/flask-jwt-extended/llms.txt Use `get_current_user()` as a function call equivalent to the `current_user` proxy. It raises a `RuntimeError` if called outside a protected context or without a registered `user_lookup_loader`. ```python from flask import Flask, jsonify from flask_jwt_extended import JWTManager, jwt_required, get_current_user app = Flask(__name__) app.config["JWT_SECRET_KEY"] = "super-secret" jwt = JWTManager(app) # Assumes user_lookup_loader is configured (see current_user example above) @app.route("/profile") @jwt_required() def profile(): user = get_current_user() if user is None: return jsonify(msg="User not found"), 404 return jsonify(username=user.username) ``` -------------------------------- ### JWTManager Initialization Source: https://context7.com/vimalloc/flask-jwt-extended/llms.txt Initializes the JWTManager extension with a Flask application. This can be done directly or using the application factory pattern. It also shows how to enable the Jinja2 context processor. ```APIDOC ## JWTManager — Initialize the Extension `JWTManager` registers Flask-JWT-Extended with a Flask app, wires up all error handlers, and stores all callback configuration. It supports both the direct constructor pattern and the application factory (`init_app`) pattern. ```python from flask import Flask from flask_jwt_extended import JWTManager # --- Direct pattern --- app = Flask(__name__) app.config["JWT_SECRET_KEY"] = "super-secret" # Change this in production! jwt = JWTManager(app) # --- Application factory pattern --- jwt = JWTManager() def create_app(): app = Flask(__name__) app.config["JWT_SECRET_KEY"] = "super-secret" jwt.init_app(app) return app # --- With Jinja2 context processor (makes current_user available in templates) --- jwt = JWTManager(app, add_context_processor=True) ``` ``` -------------------------------- ### Dynamic Signing Keys with JWTManager Source: https://context7.com/vimalloc/flask-jwt-extended/llms.txt Implement dynamic key loading for JWT encoding and decoding. This is useful for multi-tenant applications or key rotation with asymmetric algorithms. Ensure the necessary PEM files are accessible. ```python from flask import Flask, jsonify from flask_jwt_extended import JWTManager, create_access_token, jwt_required app = Flask(__name__) app.config["JWT_ALGORITHM"] = "RS256" app.config["JWT_PUBLIC_KEY"] = open("public.pem").read() app.config["JWT_PRIVATE_KEY"] = open("private.pem").read() jwt = JWTManager(app) TENANT_KEYS = { "tenant-a": {"private": open("tenant_a_private.pem").read(), "public": open("tenant_a_public.pem").read()}, "tenant-b": {"private": open("tenant_b_private.pem").read(), "public": open("tenant_b_public.pem").read()}, } @jwt.encode_key_loader def encode_key_loader(identity): # identity is the raw value passed to create_access_token tenant = identity.get("tenant", "default") return TENANT_KEYS.get(tenant, {}).get("private", app.config["JWT_PRIVATE_KEY"]) @jwt.decode_key_loader def decode_key_loader(jwt_header, jwt_payload): # Select decode key based on unverified payload tenant = jwt_payload.get("tenant", "default") return TENANT_KEYS.get(tenant, {}).get("public", app.config["JWT_PUBLIC_KEY"]) ``` -------------------------------- ### Get JWT Header Dictionary Source: https://context7.com/vimalloc/flask-jwt-extended/llms.txt Use `get_jwt_header()` to retrieve the decoded JWT header. This includes standard fields like `alg` and `typ`, as well as any custom headers added via `additional_headers_loader`. ```python from flask import Flask, jsonify from flask_jwt_extended import JWTManager, create_access_token, jwt_required, get_jwt_header app = Flask(__name__) app.config["JWT_SECRET_KEY"] = "super-secret" jwt = JWTManager(app) @app.route("/login", methods=["POST"]) def login(): token = create_access_token( identity="alice", additional_headers={"kid": "signing-key-2024"}, ) return jsonify(access_token=token) @app.route("/header-info") @jwt_required() def header_info(): header = get_jwt_header() return jsonify(algorithm=header["alg"], key_id=header.get("kid")) # → {"algorithm": "HS256", "key_id": "signing-key-2024"} ``` -------------------------------- ### Refresh Route: Create a New Access Token Source: https://github.com/vimalloc/flask-jwt-extended/blob/main/docs/refreshing_tokens.md This route allows clients to obtain a new access token using a valid refresh token. The newly created access token is marked as not fresh. ```python @app.route("/refresh", methods=["POST"]) @jwt_required(refresh=True) def refresh(): identity = get_jwt_identity() access_token = create_access_token(identity=identity, fresh=False) return jsonify(access_token=access_token) ``` -------------------------------- ### Initialize JWTManager in Flask Source: https://context7.com/vimalloc/flask-jwt-extended/llms.txt Initialize JWTManager with a Flask app using either the direct constructor or the application factory pattern. Optionally enable the Jinja2 context processor to make `current_user` available in templates. ```python from flask import Flask from flask_jwt_extended import JWTManager # --- Direct pattern --- app = Flask(__name__) app.config["JWT_SECRET_KEY"] = "super-secret" # Change this in production! jwt = JWTManager(app) # --- Application factory pattern --- jwt = JWTManager() def create_app(): app = Flask(__name__) app.config["JWT_SECRET_KEY"] = "super-secret" jwt.init_app(app) return app # --- With Jinja2 context processor (makes current_user available in templates) --- jwt = JWTManager(app, add_context_processor=True) ``` -------------------------------- ### Implicit JWT Refreshing with Cookies Source: https://github.com/vimalloc/flask-jwt-extended/blob/main/docs/refreshing_tokens.md This example demonstrates how to automatically refresh JWTs that are close to expiring. It uses an `after_request` callback to check the expiration time and set new cookies if necessary. Ensure `JWT_COOKIE_SECURE` is set to `True` in production. ```python from datetime import datetime from datetime import timedelta from datetime import timezone from flask import Flask from flask import jsonify from flask_jwt_extended import create_access_token from flask_jwt_extended import get_jwt from flask_jwt_extended import get_jwt_identity from flask_jwt_extended import jwt_required from flask_jwt_extended import JWTManager from flask_jwt_extended import set_access_cookies from flask_jwt_extended import unset_jwt_cookies app = Flask(__name__) # If true this will only allow the cookies that contain your JWTs to be sent # over https. In production, this should always be set to True app.config["JWT_COOKIE_SECURE"] = False app.config["JWT_TOKEN_LOCATION"] = ["cookies"] app.config["JWT_SECRET_KEY"] = "super-secret" # Change this in your code! app.config["JWT_ACCESS_TOKEN_EXPIRES"] = timedelta(hours=1) jwt = JWTManager(app) # Using an `after_request` callback, we refresh any token that is within 30 # minutes of expiring. Change the timedeltas to match the needs of your application. @app.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()) set_access_cookies(response, access_token) return response except (RuntimeError, KeyError): # Case where there is not a valid JWT. Just return the original response return response @app.route("/login", methods=["POST"]) def login(): response = jsonify({"msg": "login successful"}) access_token = create_access_token(identity="example_user") set_access_cookies(response, access_token) return response @app.route("/logout", methods=["POST"]) def logout(): response = jsonify({"msg": "logout successful"}) unset_jwt_cookies(response) return response @app.route("/protected") @jwt_required() def protected(): return jsonify(foo="bar") if __name__ == "__main__": app.run() ``` -------------------------------- ### create_access_token Source: https://context7.com/vimalloc/flask-jwt-extended/llms.txt Creates a signed access token for a given identity. Supports basic tokens, fresh tokens, tokens with custom claims and headers, and tokens that do not expire. ```APIDOC ## create_access_token — Create an Access JWT Creates a signed access token for the given identity. Accepts optional freshness flag, custom expiry, additional claims, and additional headers. ```python from datetime import timedelta from flask import Flask, jsonify, request from flask_jwt_extended import JWTManager, create_access_token app = Flask(__name__) app.config["JWT_SECRET_KEY"] = "super-secret" jwt = JWTManager(app) @app.route("/login", methods=["POST"]) def login(): username = request.json.get("username") password = request.json.get("password") if username != "test" or password != "test": return jsonify({"msg": "Bad username or password"}), 401 # Basic token access_token = create_access_token(identity=username) # Fresh token (for sensitive operations), expires in 1 hour fresh_token = create_access_token( identity=username, fresh=True, expires_delta=timedelta(hours=1), ) # Token with additional claims merged in token_with_claims = create_access_token( identity=username, additional_claims={"role": "admin", "aud": "my-app"}, additional_headers={"kid": "key-id-1"}, ) # Token that never expires (DANGEROUS – avoid in production) no_expire_token = create_access_token(identity=username, expires_delta=False) return jsonify( access_token=access_token, fresh_token=fresh_token, token_with_claims=token_with_claims, ) ``` ``` -------------------------------- ### Protected Route: Require Fresh Access Token Source: https://github.com/vimalloc/flask-jwt-extended/blob/main/docs/refreshing_tokens.md This route is protected and can only be accessed with a fresh access token. The `fresh=True` argument ensures that only recently issued or re-issued fresh tokens are accepted. ```python @app.route("/protected", methods=["GET"]) @jwt_required(fresh=True) def protected(): return jsonify(foo="bar") ``` -------------------------------- ### User Lookup Loader Source: https://context7.com/vimalloc/flask-jwt-extended/llms.txt Registers a callback to load a user object from a data source on each protected request. The returned object is accessible via `current_user`. Returning `None` signals a lookup failure. ```APIDOC ## @jwt.user_lookup_loader — Deserialize Identity Into a User Object Registers a callback to load a user object from the database (or any source) on each protected request. The returned object is accessible via `current_user`. Return `None` to signal a lookup failure (user deleted, etc.). ```python from flask import Flask, jsonify from flask_jwt_extended import JWTManager, jwt_required, current_user app = Flask(__name__) app.config["JWT_SECRET_KEY"] = "super-secret" jwt = JWTManager(app) USERS = {1: {"id": 1, "username": "alice"}, 2: {"id": 2, "username": "bob"}} @jwt.user_lookup_loader def user_lookup_callback(jwt_header, jwt_data): identity = jwt_data["sub"] return USERS.get(identity) # Return None if not found → 401 @app.route("/me") @jwt_required() def me(): return jsonify(current_user) ``` ``` -------------------------------- ### Flask-JWT-Extended Core Configuration Options Source: https://context7.com/vimalloc/flask-jwt-extended/llms.txt Configure essential JWT settings like secret key, algorithms, and token expiration times. JWT_SECRET_KEY is required for HS* algorithms. ```python from datetime import timedelta from flask import Flask from flask_jwt_extended import JWTManager app = Flask(__name__) # --- Core --- app.config["JWT_SECRET_KEY"] = "change-me-in-production" # REQUIRED for HS* algorithms app.config["JWT_ALGORITHM"] = "HS256" # Default signing algorithm app.config["JWT_ACCESS_TOKEN_EXPIRES"] = timedelta(minutes=15) # Default: 15 minutes app.config["JWT_REFRESH_TOKEN_EXPIRES"] = timedelta(days=30) # Default: 30 days app.config["JWT_IDENTITY_CLAIM"] = "sub" # Claim key for identity app.config["JWT_ERROR_MESSAGE_KEY"] = "msg" # Key in error JSON response ```