05 May 2017, a calm Friday at 21:51 · Flask Python

Flask jwt optional

I needed JWT for some web application, someone provides a flask extension on top of Python-JWT, called Flask JWT obviously, the thing is I thought that flask-jwt automatically pushes the current identity to the request context but it seems it's not the case (meaning that even if the authorization token is passed the current_identity will stay None if you didn't use jwt_required()), so I wrote a simple wrapper you can use this wrapper like jwt_required, when you need to access current_identity, I think that this is how Flask-JWT should work by default, but anyways here is the code:

from flask_jwt import _jwt
from flask import _request_ctx_stack
from functools import wraps
import jwt

def jwt_optional(realm=None):
    def wrapper(fn):
        @wraps(fn)
        def decorator(*args, **kwargs):
            token = _jwt.request_callback()
            try:
                payload = _jwt.jwt_decode_callback(token)
            except jwt.exceptions.DecodeError:
                pass
            else:
                _request_ctx_stack.top.current_identity = _jwt.identity_callback(payload)
            return fn(*args, **kwargs)
        return decorator
    return wrapper

Usage:

from flask_jwt import current_identity

@app.route('/')
@jwt_optional()
def home():
    if current_identity:
        """
        Do some stuff that authorized users do
        """
    else:
        """
        Do some stuff that non authorized users do
        """

I really think that this should be default in Flask-JWT, so IMHO a more sane way to approach this is to register a before_request callback, like this:

@app.before_request
def push_to_ctx():
    token = _jwt.request_callback()
    try:
        payload = _jwt.jwt_decode_callback(token)
    except jwt.exceptions.DecodeError:
        pass
    else:
        _request_ctx_stack.top.current_identity = _jwt.identity_callback(payload)
Comments powered by Disqus