lepture / authlib

The ultimate Python library in building OAuth, OpenID Connect clients and servers. JWS,JWE,JWK,JWA,JWT included.
https://authlib.org/
BSD 3-Clause "New" or "Revised" License
4.49k stars 448 forks source link

Inability for automatic token refresh when using `grant_type=password` #532

Open mabuelatta-cohere opened 1 year ago

mabuelatta-cohere commented 1 year ago

Describe the bug

Trying to authenticate and generate requests using an OAuth2Session using username/password authentication. I'm able to generate an initial token to be used in my session, however, I was trying to utilize the functionality to automatically refresh tokens by passing in the token_endpoint to automatically as stated in the documentation.

When my token would expire it would not refresh the token automatically and lead to an InvalidToken error. After looking into this further I tried to invoke the authorization to refresh and generate a new token by passing in the grant_type=password as one of the recognized metadata that gets passed into the client. However noticed that this will not properly resolve the problem as the ensure_active_token is used to automatically refresh tokens:

https://github.com/lepture/authlib/blob/a2ada05dae625695f559140675a8d2aebc6b5974/authlib/oauth2/client.py#L256-L269

is neglecting to pass in the rest of the metadata from the session (like grant_type) to refresh_token here https://github.com/lepture/authlib/blob/a2ada05dae625695f559140675a8d2aebc6b5974/authlib/oauth2/client.py#L222-L254

that only uses passed-in params to construct the body to generate a new token through prepare_token_request here:

https://github.com/lepture/authlib/blob/a2ada05dae625695f559140675a8d2aebc6b5974/authlib/oauth2/client.py#L238-L241

Error Stacks

File 
"/Users/mamdouh.abuelatta/.local/share/virtualenvs/optic-dr-ETdtnlpf/lib/python3.8/site-packages/authlib/integrations/requests_client/oauth2_session.py
", line 109, in request
    return super(OAuth2Session, self).request(
  File 
"/Users/mamdouh.abuelatta/.local/share/virtualenvs/optic-dr-ETdtnlpf/lib/python3.8/site-packages/requests/sessions.py
", line 528, in request
    prep = self.prepare_request(req)
  File 
"/Users/mamdouh.abuelatta/.local/share/virtualenvs/optic-dr-ETdtnlpf/lib/python3.8/site-packages/requests/sessions.py
", line 456, in prepare_request
    p.prepare(
  File 
"/Users/mamdouh.abuelatta/.local/share/virtualenvs/optic-dr-ETdtnlpf/lib/python3.8/site-packages/requests/models.py
", line 320, in prepare
    self.prepare_auth(auth, url)
  File 
"/Users/mamdouh.abuelatta/.local/share/virtualenvs/optic-dr-ETdtnlpf/lib/python3.8/site-packages/requests/models.py
", line 556, in prepare_auth
    r = auth(self)
  File 
"/Users/mamdouh.abuelatta/.local/share/virtualenvs/optic-dr-ETdtnlpf/lib/python3.8/site-packages/authlib/integrations/requests_client/oauth2_session.py
", line 24, in __call__
    self.ensure_active_token()
  File 
"/Users/mamdouh.abuelatta/.local/share/virtualenvs/optic-dr-ETdtnlpf/lib/python3.8/site-packages/authlib/integrations/requests_client/oauth2_session.py
", line 21, in ensure_active_token
    raise InvalidTokenError()
authlib.integrations.base_client.errors.InvalidTokenError: token_invalid: 

During handling of the above exception, another exception occurred:

Traceback (most recent call last):

To Reproduce

A minimal example to reproduce the behavior:

  1. Initialize OAuth2Session with a valid token_endpoint and grant_type=password
  2. fetch_token with username/password
  3. Wait for(or manipulate token expiry) token to be in an expired state
  4. Use client.request to initiate a request

Expected behavior

Ability to pass grant_type=password and allow for automatic refresh token when the initial token has expired.

Environment:

Proposed Solution

A. Pass in the rest of the metadata from the session (like grant_type) to refresh_token here:https://github.com/lepture/authlib/blob/a2ada05dae625695f559140675a8d2aebc6b5974/authlib/oauth2/client.py#L222-L254

that will be passed-down as a params to construct the body to generate a new token through prepare_token_request here:

https://github.com/lepture/authlib/blob/a2ada05dae625695f559140675a8d2aebc6b5974/authlib/oauth2/client.py#L238-L241

B. Pass in combined params (method/session) when constructing the body to generate a new token through prepare_token_request here:

https://github.com/lepture/authlib/blob/a2ada05dae625695f559140675a8d2aebc6b5974/authlib/oauth2/client.py#L238-L241