Changing Default Behaviors

Changing callback functions

We provide what we think are sensible behaviors when attempting to access a protected endpoint. If the access token is not valid for any reason (missing, expired, tampered with, etc) we will return json in the format of {‘msg’: ‘why accessing endpoint failed’} along with an appropriate http status code (generally 401 or 422). However, you may want to customize what you return in some situations. We can do that with the jwt_manager loader functions.

from flask import Flask, jsonify, request
from flask_jwt_extended import (
    JWTManager, jwt_required, create_access_token
)

app = Flask(__name__)

app.config['JWT_SECRET_KEY'] = 'super-secret'  # Change this!
jwt = JWTManager(app)


# Using the expired_token_loader decorator, we will now call
# this function whenever an expired but otherwise valid access
# token attempts to access an endpoint
@jwt.expired_token_loader
def my_expired_token_callback():
    return jsonify({
        'status': 401,
        'sub_status': 42,
        'msg': 'The token has expired'
    }), 401


@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

    ret = {'access_token': create_access_token(username)}
    return jsonify(ret), 200


@app.route('/protected', methods=['GET'])
@jwt_required
def protected():
    return jsonify({'hello': 'world'}), 200


if __name__ == '__main__':
    app.run()

Here are the possible loader functions. Click on the links for a more more details about what arguments your callback functions should expect and what the return values of your callback functions need to be.

Loader Decorator Description
expired_token_loader() Function to call when an expired token accesses a protected endpoint
invalid_token_loader() Function to call when an invalid token accesses a protected endpoint
unauthorized_loader() Function to call when a request with no JWT accesses a protected endpoint
needs_fresh_token_loader() Function to call when a non-fresh token accesses a fresh_jwt_required() endpoint
revoked_token_loader() Function to call when a revoked token accesses a protected endpoint
user_loader_callback_loader() Function to call to load a user object when token accesses a protected endpoint
user_loader_error_loader() Function that is called when the user_loader callback function returns None
token_in_blacklist_loader() Function that is called to check if a token has been revoked
claims_verification_loader() Function that is called to verify the user_claims data. Must return True or False
claims_verification_failed_loader() Function that is called when the user claims verification callback returns False

Dynamic token expires time

You can also change the expires time for a token via the expires_delta kwarg in the create_refresh_token() and create_access_token() functions. This takes a datetime.timedelta and overrides the JWT_REFRESH_TOKEN_EXPIRES and JWT_ACCESS_TOKEN_EXPIRES settings (see Configuration Options).

This can be useful if you have different use cases for different tokens. For example, you might use short lived access tokens used in your web application, but you allow the creation of long lived access tokens that other developers can generate and use to interact with your api in their programs. You could accomplish this like such:

@app.route('/create-dev-token', methods=['POST'])
@jwt_required
def create_dev_token():
    username = get_jwt_identity()
    expires = datetime.timedelta(days=365)
    token = create_access_token(username, expires_delta=expires)
    return jsonify({'token': token}), 201

You can even disable expiration by setting expires_delta to False:

@app.route('/create-api-token', methods=['POST'])
@jwt_required
def create_api_token():
    username = get_jwt_identity()
    token = create_access_token(username, expires_delta=False)
    return jsonify({'token': token}), 201

Note that in this case, you should enable token revoking (see Blacklist and Token Revoking).