1

I am trying to implement a Oauth2 provider server in Python from  https://github.com/lepture/flask-oauthlib/tree/master/tests/oauth2/server.py code base but stuck when trying to do some redirect uri validation customization for the Oauth2 grant (type= authorization code) flow.

According to Oauth2.py, I should be able add a function called validate_redirect_uri() to do my own customized redirect_uri validation. However, after implementing "def validate_redirect_uri(self, redirect_uri):" in Grant class, found it was never invoked when I POST to /oauth/authorize with parameters like "response_type=code&client_id=confidential&redirect_uri=https%3A%2F%2fXXX.com%2Foauth%2Fcallback%3FXXX%3D111&state=11"

I am sure that the post is fine (scope was put to POST body so it was not missing) because if I only alter the redirect_uri to a NOT customized one, it grants just fine.

in Server.py:

@oauth.grantgetter
def get_grant(client_id, code):
    return Grant.query.filter_by(client_id=client_id, code=code).first()

class Grant(db.Model):

def validate_redirect_uri(self, redirect_uri):
    print('validate_redirect_uri:', redirect_uri,'\n')
    if customizedValidateRedirectURI(redirect_uri)!=-1:
        print('valid redirect uri')
        return True
    return False

def delete(self):
    db.session.delete(self)
    db.session.commit()
    return self

in oauth2.py

def confirm_redirect_uri(self, client_id, code, redirect_uri, client,
                         *args, **kwargs):
    """Ensure client is authorized to redirect to the redirect_uri.

    This method is used in the authorization code grant flow. It will
    compare redirect_uri and the one in grant token strictly, you can
    add a `validate_redirect_uri` function on grant for a customized
    validation.
    """
    client = client or self._clientgetter(client_id)
    log.debug('Confirm redirect uri for client %r and code %r.',
              client.client_id, code)
    grant = self._grantgetter(client_id=client.client_id, code=code)
    if not grant:
        log.debug('Grant not found.')
        return False
    if hasattr(grant, 'validate_redirect_uri'):
        return grant.validate_redirect_uri(redirect_uri)

"print('validate_redirect_uri:', redirect_uri,'\n')" was never printed so the function "validate_redirect_uri(self, redirect_uri)" never got invoked?

3 Answers3

0

According to the comment of confirm_redirect_uri, it is implied that confirm_redirect_uri is called when you make a token request, not an authorization request.

If an authorization request using the authorization code flow includes a redirect_uri request parameter, the token request that corresponds to the authorization request must include a redirect_uri request parameter with the same value. See RFC 6749, 4.1.3. Access Token Request for details.

Probably, confirm_redirect_uri is used to confirm that the redirect URI included in the authorization request matches the redirect URI included in the corresponding token request. Therefore, your validate_redirect_uri is not invoked in the context of an authorization request.

Community
  • 1
  • 1
Takahiko Kawasaki
  • 18,118
  • 9
  • 62
  • 105
  • I tried a different way to inherit and create a class MyValidator(OAuth2RequestValidator) then override the validate_redirect_uri() function. then try to use oauth._validator = MyValidator(clientgetter=oauth.clientgetter, ...) to replace the default validator in provider. This time validate_redirect_uri() got invoked. But running into another issue that below errors occorred when authorize: " return set(client.default_scopes).... AttributeError: 'str' object has no attribute 'default_scopes'" Should be wrong obj type of client in MyValidator. But couldn't figure out how to fix... – Michael Zhou Aug 29 '19 at 05:08
  • Probably, validating a redirect URI is more complicated than you may imagine. Please read "8.1. Redirect URI Validation" in "[Full-Scratch Implementor of OAuth and OpenID Connect Talks About Findings](https://medium.com/@darutk/full-scratch-implementor-of-oauth-and-openid-connect-talks-about-findings-55015f36d1c3)". – Takahiko Kawasaki Aug 29 '19 at 05:13
0

Fix the problem by below way:

class MyValidator(OAuth2RequestValidator):

def validate_redirect_uri(self, redirect_uri):
    print('validate_redirect_uri:', redirect_uri,'\n')
    if customizedValidateRedirectURI(redirect_uri)!=-1:
        print('valid redirect uri')
        return True
    return False

def default_provider(app): oauth = OAuth2Provider(app)

skip bunch of @oauth.xxgetter/xxsetter

oauth._validator = MyValidator(
    clientgetter=get_client,
    tokengetter=get_token,
    grantgetter=get_grant,
    usergetter=get_user,
    tokensetter=set_token,
    grantsetter=set_grant,
    )
0

I'm the author of Flask-OAuthlib. Please switch to Authlib instead. Checkout the example code here:

  1. https://github.com/authlib/example-oauth2-server
  2. https://github.com/authlib/example-oidc-server
lepture
  • 2,307
  • 16
  • 18