Scope changes with Microsoft services & `offline_access`
attie-argentum opened this issue · 0 comments
attie-argentum commented
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:
offline_access
https://outlook.office.com/User.Read
https://outlook.office.com/IMAP.AccessAsUser.All
The service responds with the following (i.e: offline_access
is removed):
https://outlook.office.com/User.Read
https://outlook.office.com/IMAP.AccessAsUser.All
This results in a warning being raised.
Traceback
Traceback (most recent call last):
File "./oauth2-test.py", line 51, in <module>
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?
- A more generic mechanism to permit accepting scope changes
- A way to supply the expected response set of scopes
- A list of "I don't mind if these aren't grated" scopes