requests / requests-oauthlib

OAuthlib support for Python-Requests!
https://requests-oauthlib.readthedocs.org/
ISC License
1.71k stars 421 forks source link

Scope changes with Microsoft services & `offline_access` #507

Open attie-argentum opened 1 year ago

attie-argentum commented 1 year ago

I'm trying to set up OAuth2 for unattended access to Microsoft IMAP servers - the refresh_token is important here.

When providing a request scope set as follows:

The service responds with the following (i.e: offline_access is removed):

This results in a warning being raised.

Traceback ``` Traceback (most recent call last): File "./oauth2-test.py", line 51, in token = oauth.fetch_token(token_url, client_secret=client_secret, authorization_response=redirect_response) File "/usr/lib/python3.8/site-packages/requests_oauthlib/oauth2_session.py", line 366, in fetch_token self._client.parse_request_body_response(r.text, scope=self.scope) File "/usr/lib/python3.8/site-packages/oauthlib/oauth2/rfc6749/clients/base.py", line 427, in parse_request_body_response self.token = parse_token_response(body, scope=scope) File "/usr/lib/python3.8/site-packages/oauthlib/oauth2/rfc6749/parameters.py", line 441, in parse_token_response validate_token_parameters(params) File "/usr/lib/python3.8/site-packages/oauthlib/oauth2/rfc6749/parameters.py", line 471, in validate_token_parameters raise w Warning: Scope has changed from "https://outlook.office.com/User.Read https://outlook.office.com/IMAP.AccessAsUser.All offline_access" to "https://outlook.office.com/User.Read https://outlook.office.com/IMAP.AccessAsUser.All". ```

Apparently the offline_access scope should never be returned by Microsoft services, as it's not actually a useful scope for accessing resources (ref).


My current approach (which isn't ideal), is as follows:

oauth = OAuth2Session(client_id, redirect_uri=redirect_uri, scope=scope)
authorization_url, state = oauth.authorization_url(authorize_url)

# remove the `offline_access` scope directly / by hand
oauth.scope.remove('offline_access')

# ... submit the request to authorization_url, and retrieve the token
redirect_response = ...
token = oauth.fetch_token(token_url, client_secret=client_secret, authorization_response=redirect_response)

I'm aware of OAUTHLIB_RELAX_TOKEN_SCOPE (link), but that seems perhaps a little over-permissive.

Perhaps one of the following would be a good idea?