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
def my_expired_token_callback(expired_token):
    token_type = expired_token['type']
    return jsonify({
        'status': 401,
        'sub_status': 42,
        'msg': 'The {} token has expired'.format(token_type)
    }), 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'])
def protected():
    return jsonify({'hello': 'world'}), 200

if __name__ == '__main__':

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



Function that is called to verify the user_claims data. Must return True or False


Function that is called when the user claims verification callback returns False


Function that is called to get the decode key before verifying a token


Function that is called to get the encode key before creating a token


Function to call when an expired token accesses a protected endpoint


Function to call when an invalid token accesses a protected endpoint


Function to call when a non-fresh token accesses a fresh_jwt_required() endpoint


Function to call when a revoked token accesses a protected endpoint


Function that is called to check if a token has been revoked


Function to call when a request with no JWT accesses a protected endpoint


Function to call to load a user object when token accesses a protected endpoint


Function that is called when the user_loader callback function returns None

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'])
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'])
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).