Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

authorize_access_token does not raise OAuthErrors in an error response callback #275

Closed
sm-Fifteen opened this issue Sep 22, 2020 · 1 comment
Assignees
Labels

Comments

@sm-Fifteen
Copy link

sm-Fifteen commented Sep 22, 2020

Describe the bug

When using AuthLib framework integrations in an OAuth2 Authorization Code Grant flow (among others), the authorization server may call the OAuth callback endpoint with an error code and nothing else (such as if the user pressed "Cancel" on the auth form, usually leading to an "Access denied" error message). Calling authorize_access_token on the RemoteApp object like the code examples show will not cause the appropriate exceptions to be raised. Under most circumstances, calling something like localhost:8000/auth?error=access_denied&error_description=Request denied by the user. will cause authlib to throw a MismatchingStateError if state validation was used and a rather strange 'code not specified' error if it is suppressed (such as by adding oauth.gitfacehubbook.framework.set_session_data(req, 'state', None) before the call to authorize_access_token).

Error Stacks

With state validation:

Traceback (most recent call last):
  *snip*
  File "pyenv\lib\site-packages\authlib\integrations\starlette_client\integration.py", line 56, in authorize_access_token
    params = self.retrieve_access_token_params(request)
  File "pyenv\lib\site-packages\authlib\integrations\base_client\base_app.py", line 144, in retrieve_access_token_params
    params = self._retrieve_oauth2_access_token_params(request, params)
  File "pyenv\lib\site-packages\authlib\integrations\base_client\base_app.py", line 125, in _retrieve_oauth2_access_token_params
    raise MismatchingStateError()
authlib.integrations.base_client.errors.MismatchingStateError: mismatching_state: CSRF Warning! State not equal in request and response.

Without state validation:

Traceback (most recent call last):
  *snip*
  File "pyenv\lib\site-packages\authlib\integrations\starlette_client\integration.py", line 58, in authorize_access_token
    return await self.fetch_access_token(**params)
  File "pyenv\lib\site-packages\authlib\integrations\base_client\async_app.py", line 105, in fetch_access_token
    token = await client.fetch_token(token_endpoint, **kwargs)
  File "pyenv\lib\site-packages\authlib\integrations\httpx_client\oauth2_client.py", line 116, in _fetch_token
    return self.parse_response_token(resp.json())
  File "pyenv\lib\site-packages\authlib\oauth2\client.py", line 380, in parse_response_token
    self.handle_error(error, description)
  File "pyenv\lib\site-packages\authlib\integrations\httpx_client\oauth2_client.py", line 72, in handle_error
    raise OAuthError(error_type, error_description)
authlib.integrations.base_client.errors.OAuthError: {'code': 400, 'error': 'invalid_request', 'error_description': 'code not specified', 'message': 'code not specified', 'details': []}: {'code': 400, 'error': 'invalid_request', 'error_description': 'code not specified', 'message': 'code not specified', 'details': []}

To Reproduce

app = Starlette(debug=True)
app.add_middleware(SessionMiddleware, secret_key="!secret")

config = Config('.env')
oauth = OAuth(config)

CONF_URL = 'https://accounts.google.com/.well-known/openid-configuration'
oauth.register(
    name='google',
    server_metadata_url=CONF_URL,
    client_kwargs={
        'scope': 'openid email profile'
    }
)

@app.route('/auth')
async def auth(request):
    token = await oauth.google.authorize_access_token(request)
    pass

Call /auth?error=access_denied&error_description=Request denied by the user. on that application. Google does not have a cancel button on its form and I'm not aware of any circumstance where it would send an error message to your callback, but it would be standard-compliant to do so and some authorization servers will.

Expected behavior

authorize_access_token should check what the passed request's query params are and raise the appropriate OAuthError for the given error_code value (which is a spec-defined closed set) instead of a generic one. It would be up to the user to decide whether to handle these errors by checking the error code before that call or in an exception handler. Uncaught errors would At least bubble up and give an appropriate error message to the developer.

Alternatively, the error handling part could be split in a separate RemoteApp method to be called at the developper's discretion before authorize_access_token.

Environment:

  • OS: Windows 10
  • Python Version: 3.8.0
  • Authlib Version: 0.14.3
@lepture
Copy link
Owner

lepture commented Oct 1, 2020

Thanks for your report. I've fixed this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants