puiterwijk / flask-oidc

OpenID Connect support for Flask
BSD 2-Clause "Simplified" License
154 stars 217 forks source link

Read access token from header #123

Open Maxinger15 opened 3 years ago

Maxinger15 commented 3 years ago

I am currently developing the first api with flask and flask-oidc and I noticed that is not possible (or not documented how) to read the token from the Authorization header field. As I saw it just works as a attribute named access_token in the query or in the body as a form.

@blueprint_SequenzData.route('/', methods=['GET'])
@oidc.accept_token(require_token=True, scopes_required=['openid'])
def sequenzdata():
    data = SequenzData.objects().to_json()
    return Response(data,mimetype="application/json",status=200)

This has two disadvantages for me.

Query -> Really long URL (depending an request it get close to the maximum url length of 2048 Chars Body -> Forces to use the x-www-urlencoded or form-data body type which breaks json only API coding.

Is there a way to submit the access token via an "Authorization" : "Bearer " header like described here: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization

mcejp commented 3 years ago

If you just need to verify a JWT token, without any of the authorization flows, session management etc., you might be better off ditching this unmaintained library (see #85) and decoding the token directly via PyJWT, which will also validate the signature and expiration by default.

It's really not difficult, here is a very basic example, including a decorator:

def decode_access_token(token):
    pubkey = "<public key of your IDP>"

    payload = jwt.decode(token, key=pubkey, algorithms=["RS256"], leeway=5)
    logging.debug("jwt.decode => %s", payload)

    return payload

def with_bearer_token(function):
    @functools.wraps(function)
    def wrapped(*args, **kwargs):
        try:
            token = request.headers['Authorization'].split(None, 1)[1].strip()
        except KeyError:
            logging.exception("Authorization header missing")
            abort(http.HTTPStatus.UNAUTHORIZED) # FIXME: must include WWW-Authenticate with this

        try:
            g._access_token = decode_access_token(token)
        except jwt.PyJWTError:
            logging.exception("Failed to validate client token")
            abort(http.HTTPStatus.UNAUTHORIZED) # FIXME: must include WWW-Authenticate with this

        return function(*args, **kwargs)

    return wrapped

There are ways to also avoid having to hard-code the public key.

See also https://pyjwt.readthedocs.io/en/stable/usage.html#encoding-decoding-tokens-with-rs256-rsa