Search code examples
pythonflaskoauth-2.0authlib

Authlib Token Validator using Remote Authentication Server


The Authlib documentation describes how a resource server can validate the auth_token from the client implementing a BearerTokenValidator as such:

    class MyBearerTokenValidator(BearerTokenValidator):
        def authenticate_token(self, token_string):
            return Token.query.filter_by(access_token=token_string).first()

    require_oauth = ResourceProtector()
    require_oauth.register_token_validator(MyBearerTokenValidator())

    # protecting the resource
    @app.route('/user')
    @require_oauth()
    def user_profile():
        user = current_token.user
        return jsonify(user)

https://docs.authlib.org/en/stable/flask/2/resource-server.html

This solution assumes the Resource server has access to the db where the Authentication server (AS) manages the token, using the ORM tool like SQLAlchemy.

In my case, I don't have access to the token db and the AS only provides a REST introspection endpoint to validate whether the token is valid.

I am planning to use the requests library and pass the token to the AS to implement my token validator

class MyBearerTokenValidator(BearerTokenValidator):
    def authenticate_token(self, token_string):
    resp = requests.post("https://oauth-server-host/oauth/v2/introspection", auth=(id, secret), data={"token": "TK"})
    return resp.json()

Is this the correct approach or is there a better, more standard approach?


Solution

  • According to the Authlib documentation, there is a built-in approach to this problem. Thanks @lepture for pointing this out in the comments.

    We can extend a built-in IntrospectTokenValidator to implement our validator.

    from authlib.oauth2.rfc7662 import IntrospectTokenValidator
    from your_project import secrets
    
    class MyIntrospectTokenValidator(IntrospectTokenValidator):
        def introspect_token(self, token_string):
            url = 'https://example.com/oauth/introspect'
            data = {'token': token_string, 'token_type_hint': 'access_token'}
            auth = (secrets.internal_client_id, secrets.internal_client_secret)
            resp = requests.post(url, data=data, auth=auth)
            return resp.json()
    

    We can then register this token validator in to resource protector:

    require_oauth = ResourceProtector()
    require_oauth.register_token_validator(MyIntrospectTokenValidator())
    

    Source https://docs.authlib.org/en/latest/specs/rfc7662.html#use-introspection-in-resource-server