Advanced configuration of Flask-JWT

Flask-JWT adds JWT functionality to Flask in an easy to use manner. It gives you a lot of functionality out of the box, but sometimes we want to modify some of the configuration. This document walks through how to:

  • Change the authentication endpoint (by default, /auth);
  • Change the token expiration time (by default, 5 minutes);
  • Change the authentication key name (by default, username);
  • Change the authentication response body (by default, only contains access_token);
  • Change the error handler.

In addition, it covers how to retrieve the currently logged in user from any of our Flask app endpoints.

This tutorial assumes that you’ve followed the lectures and have set up Flask-JWT already! If you haven't done so yet, check out Section 5 of the Udemy course.

Before We Start

First, let’s take a look at what we already have here.
In our app.py file, we should already set up the JWT using the below code:

from flask_jwt import JWT
from security import authenticate, identity

jwt = JWT(app, authenticate, identity)  # /auth

And in our security.py file, we should have something like this:

from werkzeug.security import safe_str_cmp
from models.user import UserModel

def authenticate(username, password):
    user = UserModel.find_by_username(username)
    if user and safe_str_cmp(user.password, password):
        return user

def identity(payload):
    user_id = payload['identity']
    return UserModel.find_by_id(user_id)

Configuration

Authentication URL

If we want to change the url to the authentication endpoint, for instance, we want to use /login instead of /auth, we can do something like this:

app.config['JWT_AUTH_URL_RULE'] = '/login'
jwt = JWT(app, authenticate, identity)

Important: We added the second line of code to emphasize that we must change the JWT authentication URL first, before creating the JWT instance. Otherwise, our configuration won't take effect. However, it is only required for configuring the auth URL, the following confurations will still take effect after requesting the JWT instance.

Token Expiration Time

# config JWT to expire within half an hour
app.config['JWT_EXPIRATION_DELTA'] = timedelta(seconds=1800)

Authentication Key Name

# config JWT auth key name to be 'email' instead of default 'username'
app.config['JWT_AUTH_USERNAME_KEY'] = 'email'

Authentication Response Handler

Sometimes we may want to include more information in the authentication response body, not just the access_token. For example, we may also want to include the user's ID in the response body. In this case, we can do something like this:

# customize JWT auth response, include user_id in response body
from flask import jsonify
from flask_jwt import JWT

from security import authenticate, identity as identity_function
jwt = JWT(app, authenticate, identity_function)

@jwt.auth_response_handler
def customized_response_handler(access_token, identity):
    return jsonify({
                        'access_token': access_token.decode('utf-8'),
                        'user_id': identity.id
                   })

Remember that the identity should be what you've returned by the authenticate() function, and in our sample, it is a UserModel object which contains a field id. Make sure to only access valid fields in your identity model!

Moreover, it is generally not recommended to include information that is encrypted in the access_token since it may introduce security issues.

Error handler

By default, Flask-JWT raises JWTError when an error occurs within any of the handlers (e.g. during authentication, identity, or creating the response). In some cases we may want to customize what our Flask app does when such an error occurs. We can do it this way:

# customize JWT auth response, include user_id in response body
from flask import jsonify
from flask_jwt import JWT

from security import authenticate, identity as identity_function
jwt = JWT(app, authenticate, identity_function)

@jwt.error_handler
def customized_error_handler(error):
    return jsonify({
                       'message': error.description,
                       'code': error.status_code
                   }), error.status_code

Other Configurations

You may find out more configuration options here: https://pythonhosted.org/Flask-JWT/

Please refer to the <Configuration Options> section.

More

Retrieving User From Token

Another frequently asked question is: how can I get the user's identity from an access token (JWT)? Since in some cases, we not only want to guarantee that only our users can access an endpoint, but we may want to access the user's data as well. For example, if you want to restrict the access to a certain user group, not for every user. In this case, you can do something like this:

from flask_jwt import jwt_required, current_identity


class User(Resource):

    @jwt_required()
    def get(self):   # view all users
        user = current_identity
        # then implement admin auth method
        ...

Now this endpoint is protected by JWT. And you have access to the identity of the user who is interacting with this endpoint using current_identity from JWT.