def request(self, method, url, data=None, headers=None, withhold_token=False, **kwargs): """Intercept all requests and add the OAuth 2 token if present.""" if not is_secure_transport(url): raise InsecureTransportError() if self.token and not withhold_token: log.debug("Invoking %d protected resource request hooks.", len(self.compliance_hook["protected_request"])) for hook in self.compliance_hook["protected_request"]: log.debug("Invoking hook %s.", hook) url, headers, data = hook(url, headers, data) log.debug("Adding token %s to request.", self.token) try: url, headers, data = self._client.add_token(url, http_method=method, body=data, headers=headers) # Attempt to retrieve and save new access token if expired except TokenExpiredError: if self.auto_refresh_url: log.debug("Auto refresh is set, attempting to refresh at %s.", self.auto_refresh_url) token = self.refresh_token(self.auto_refresh_url, **kwargs) if self.token_updater: log.debug("Updating token to %s using %s.", token, self.token_updater) self.token_updater(token) url, headers, data = self._client.add_token(url, http_method=method, body=data, headers=headers) else: raise TokenUpdated(token) else: raise log.debug("Requesting url %s using method %s.", url, method) log.debug("Supplying headers %s and data %s", headers, data) log.debug("Passing through key word arguments %s.", kwargs) return super(OAuth2Session, self).request(method, url, headers=headers, data=data, **kwargs)
def request(self, method, url, data=None, headers=None, **kwargs): """Intercept all requests and add the OAuth 2 token if present.""" if not is_secure_transport(url): raise InsecureTransportError() if self.token: log.debug('Invoking %d protected resource request hooks.', len(self.compliance_hook['protected_request'])) for hook in self.compliance_hook['protected_request']: url, headers, data = hook(url, headers, data) try: url, headers, data = self._client.add_token(url, http_method=method, body=data, headers=headers) # Attempt to retrieve and save new access token if expired except TokenExpiredError: if self.auto_refresh_url: token = self.refresh_token(self.auto_refresh_url,auth=self.refresher.auth,**kwargs) if self.token_updater: self.token_updater(token) url, headers, data = self._client.add_token(url, http_method=method, body=data, headers=headers) else: raise TokenUpdated(token) else: raise return super(OAuth2Session, self).request(method, url, headers=headers, data=data, **kwargs)
def refresh_token(self, token_url, refresh_token=None, body='', auth=None, timeout=None, headers=None, verify=True, **kwargs): """Fetch a new access token using a refresh token. :param token_url: The token endpoint, must be HTTPS. :param refresh_token: The refresh_token to use. :param body: Optional application/x-www-form-urlencoded body to add the include in the token request. Prefer kwargs over body. :param auth: An auth tuple or method as accepted by requests. :param timeout: Timeout of the request in seconds. :param verify: Verify SSL certificate. :param kwargs: Extra parameters to include in the token request. :return: A token dict """ if not token_url: raise ValueError('No token endpoint set for auto_refresh.') if not is_secure_transport(token_url): raise InsecureTransportError() # Need to nullify token to prevent it from being added to the request refresh_token = refresh_token or self.token.get('refresh_token') self.token = {} log.debug('Adding auto refresh key word arguments %s.', self.auto_refresh_kwargs) kwargs.update(self.auto_refresh_kwargs) body = self._client.prepare_refresh_body(body=body, refresh_token=refresh_token, scope=self.scope, **kwargs) log.debug('Prepared refresh token request body %s', body) if headers is None: headers = { 'Accept': 'application/json', 'Content-Type': ( 'application/x-www-form-urlencoded;charset=UTF-8' ), } r = self.post(token_url, data=dict(urldecode(body)), auth=auth, timeout=timeout, headers=headers, verify=verify) log.debug('Request to refresh token completed with status %s.', r.status_code) log.debug('Response headers were %s and content %s.', r.headers, r.text) log.debug('Invoking %d token response hooks.', len(self.compliance_hook['refresh_token_response'])) r.raise_for_status() for hook in self.compliance_hook['refresh_token_response']: log.debug('Invoking hook %s.', hook) r = hook(r) self.token = self._client.parse_request_body_response(r.text, scope=self.scope) if not 'refresh_token' in self.token: log.debug('No new refresh token given. Re-using old.') self.token['refresh_token'] = refresh_token return self.token
def refresh_token(self, token_url, refresh_token=None, body='', auth=None, timeout=None, verify=True, **kwargs): """Fetch a new access token using a refresh token. :param token_url: The token endpoint, must be HTTPS. :param refresh_token: The refresh_token to use. :param body: Optional application/x-www-form-urlencoded body to add the include in the token request. Prefer kwargs over body. :param auth: An auth tuple or method as accepted by requests. :param timeout: Timeout of the request in seconds. :param verify: Verify SSL certificate. :param kwargs: Extra parameters to include in the token request. :return: A token dict """ if not token_url: raise ValueError('No token endpoint set for auto_refresh.') if not is_secure_transport(token_url): raise InsecureTransportError() # Need to nullify token to prevent it from being added to the request refresh_token = refresh_token or self.token.get('refresh_token') self.token = {} log.debug('Adding auto refresh key word arguments %s.', self.auto_refresh_kwargs) kwargs.update(self.auto_refresh_kwargs) body = self._client.prepare_refresh_body(body=body, refresh_token=refresh_token, scope=self.scope, **kwargs) log.debug('Prepared refresh token request body %s', body) r = self.post(token_url, data=dict(urldecode(body)), auth=auth, timeout=timeout, verify=verify) log.debug('Request to refresh token completed with status %s.', r.status_code) log.debug('Response headers were %s and content %s.', r.headers, r.text) log.debug('Invoking %d token response hooks.', len(self.compliance_hook['refresh_token_response'])) for hook in self.compliance_hook['refresh_token_response']: log.debug('Invoking hook %s.', hook) r = hook(r) self.token = self._client.parse_request_body_response(r.text, scope=self.scope) if not 'refresh_token' in self.token: log.debug('No new refresh token given. Re-using old.') self.token['refresh_token'] = refresh_token return self.token
def refresh_token( self, token_url, refresh_token=None, body="", auth=None, timeout=None, headers=None, verify=True, **kwargs ): """Fetch a new access token using a refresh token. :param token_url: The token endpoint, must be HTTPS. :param refresh_token: The refresh_token to use. :param body: Optional application/x-www-form-urlencoded body to add the include in the token request. Prefer kwargs over body. :param auth: An auth tuple or method as accepted by requests. :param timeout: Timeout of the request in seconds. :param verify: Verify SSL certificate. :param kwargs: Extra parameters to include in the token request. :return: A token dict """ if not token_url: raise ValueError("No token endpoint set for auto_refresh.") if not is_secure_transport(token_url): raise InsecureTransportError() refresh_token = refresh_token or self.token.get("refresh_token") log.debug("Adding auto refresh key word arguments %s.", self.auto_refresh_kwargs) kwargs.update(self.auto_refresh_kwargs) body = self._client.prepare_refresh_body(body=body, refresh_token=refresh_token, scope=self.scope, **kwargs) log.debug("Prepared refresh token request body %s", body) if headers is None: headers = { "Accept": "application/json", "Content-Type": ("application/x-www-form-urlencoded;charset=UTF-8"), } r = self.post( token_url, data=dict(urldecode(body)), auth=auth, timeout=timeout, headers=headers, verify=verify, withhold_token=True, ) log.debug("Request to refresh token completed with status %s.", r.status_code) log.debug("Response headers were %s and content %s.", r.headers, r.text) log.debug("Invoking %d token response hooks.", len(self.compliance_hook["refresh_token_response"])) for hook in self.compliance_hook["refresh_token_response"]: log.debug("Invoking hook %s.", hook) r = hook(r) self.token = self._client.parse_request_body_response(r.text, scope=self.scope) if not "refresh_token" in self.token: log.debug("No new refresh token given. Re-using old.") self.token["refresh_token"] = refresh_token return self.token
def __call__(self, r): """Append an OAuth 2 token to the request. Note that currently HTTPS is required for all requests. There may be a token type that allows for plain HTTP in the future and then this should be updated to allow plain HTTP on a white list basis. """ if not is_secure_transport(r.url): raise InsecureTransportError() r.url, r.headers, r.body = self._client.add_token(r.url, http_method=r.method, body=r.body, headers=r.headers) return r
def request(self, method, url, data=None, headers=None, withhold_token=False, **kwargs): """Intercept all requests and add the OAuth 2 token if present.""" if not is_secure_transport(url): raise InsecureTransportError() if self.token and not withhold_token: log.debug('Invoking %d protected resource request hooks.', len(self.compliance_hook['protected_request'])) for hook in self.compliance_hook['protected_request']: log.debug('Invoking hook %s.', hook) url, headers, data = hook(url, headers, data) log.debug('Adding token %s to request.', self.token) try: url, headers, data = self._client.add_token(url, http_method=method, body=data, headers=headers) # Attempt to retrieve and save new access token if expired except TokenExpiredError: if self.auto_refresh_url: log.debug( 'Auto refresh is set, attempting to refresh at %s.', self.auto_refresh_url) token = self.refresh_token(self.auto_refresh_url, **kwargs) if self.token_updater: log.debug('Updating token to %s using %s.', token, self.token_updater) self.token_updater(token) url, headers, data = self._client.add_token( url, http_method=method, body=data, headers=headers) else: raise TokenUpdated(token) else: raise log.debug('Requesting url %s using method %s.', url, method) log.debug('Supplying headers %s and data %s', headers, data) log.debug('Passing through key word arguments %s.', kwargs) return super(OAuth2Session, self).request(method, url, headers=headers, data=data, **kwargs)
def request(self, method, url, data=None, headers=None, withhold_token=False, client_id=None, client_secret=None, **kwargs): """Intercept all requests and add the OAuth 2 token if present.""" if not is_secure_transport(url): raise InsecureTransportError() if self.token and not withhold_token: log.debug('Invoking %d protected resource request hooks.', len(self.compliance_hook['protected_request'])) for hook in self.compliance_hook['protected_request']: log.debug('Invoking hook %s.', hook) url, headers, data = hook(url, headers, data) log.debug('Adding token %s to request.', self.token) try: url, headers, data = self._client.add_token(url, http_method=method, body=data, headers=headers) # Attempt to retrieve and save new access token if expired except TokenExpiredError: if self.auto_refresh_url: log.debug('Auto refresh is set, attempting to refresh at %s.', self.auto_refresh_url) # We mustn't pass auth twice. auth = kwargs.pop('auth', None) if client_id and client_secret and (auth is None): log.debug('Encoding client_id "%s" with client_secret as Basic auth credentials.', client_id) auth = requests.auth.HTTPBasicAuth(client_id, client_secret) token = self.refresh_token( self.auto_refresh_url, auth=auth, **kwargs ) if self.token_updater: log.debug('Updating token to %s using %s.', token, self.token_updater) self.token_updater(token) url, headers, data = self._client.add_token(url, http_method=method, body=data, headers=headers) else: raise TokenUpdated(token) else: raise log.debug('Requesting url %s using method %s.', url, method) log.debug('Supplying headers %s and data %s', headers, data) log.debug('Passing through key word arguments %s.', kwargs) return super(OAuth2Session, self).request(method, url, headers=headers, data=data, **kwargs)
async def fetch_token(self, token_url, code=None, authorization_response=None, body="", auth=None, username=None, password=None, method="POST", force_querystring=False, timeout=None, headers=None, verify_ssl=True, proxies=None, include_client_id=None, client_id=None, client_secret=None, **kwargs): """Generic method for fetching an access token from the token endpoint. If you are using the MobileApplicationClient you will want to use `token_from_fragment` instead of `fetch_token`. The current implementation enforces the RFC guidelines. :param token_url: Token endpoint URL, must use HTTPS. :param code: Authorization code (used by WebApplicationClients). :param authorization_response: Authorization response URL, the callback URL of the request back to you. Used by WebApplicationClients instead of code. :param body: Optional application/x-www-form-urlencoded body to add the include in the token request. Prefer kwargs over body. :param auth: An auth tuple or method as accepted by `requests`. :param username: Username required by LegacyApplicationClients to appear in the request body. :param password: Password required by LegacyApplicationClients to appear in the request body. :param method: The HTTP method used to make the request. Defaults to POST, but may also be GET. Other methods should be added as needed. :param force_querystring: If True, force the request body to be sent in the querystring instead. :param timeout: Timeout of the request in seconds. :param headers: Dict to default request headers with. :param verify: Verify SSL certificate. :param proxies: The `proxies` argument is passed onto `requests`. :param include_client_id: Should the request body include the `client_id` parameter. Default is `None`, which will attempt to autodetect. This can be forced to always include (True) or never include (False). :param client_secret: The `client_secret` paired to the `client_id`. This is generally required unless provided in the `auth` tuple. If the value is `None`, it will be omitted from the request, however if the value is an empty string, an empty string will be sent. :param kwargs: Extra parameters to include in the token request. :return: A token dict """ if not is_secure_transport(token_url): raise InsecureTransportError() if not code and authorization_response: log.debug('-- response %s', authorization_response) self._client.parse_request_uri_response( str(authorization_response), state=self._state) code = self._client.code log.debug('--code %s', code) elif not code and isinstance(self._client, WebApplicationClient): code = self._client.code if not code: raise ValueError("Please supply either code or " "authorization_response parameters.") # Earlier versions of this library build an HTTPBasicAuth header out of # `username` and `password`. The RFC states, however these attributes # must be in the request body and not the header. # If an upstream server is not spec compliant and requires them to # appear as an Authorization header, supply an explicit `auth` header # to this function. # This check will allow for empty strings, but not `None`. # # Refernences # 4.3.2 - Resource Owner Password Credentials Grant # https://tools.ietf.org/html/rfc6749#section-4.3.2 if isinstance(self._client, LegacyApplicationClient): if username is None: raise ValueError("`LegacyApplicationClient` requires both the " "`username` and `password` parameters.") if password is None: raise ValueError( "The required paramter `username` was supplied, " "but `password` was not.") # merge username and password into kwargs for `prepare_request_body` if username is not None: kwargs["username"] = username if password is not None: kwargs["password"] = password # is an auth explicitly supplied? if auth is not None: # if we're dealing with the default of `include_client_id` (None): # we will assume the `auth` argument is for an RFC compliant server # and we should not send the `client_id` in the body. # This approach allows us to still force the client_id by submitting # `include_client_id=True` along with an `auth` object. if include_client_id is None: include_client_id = False # otherwise we may need to create an auth header else: # since we don't have an auth header, we MAY need to create one # it is possible that we want to send the `client_id` in the body # if so, `include_client_id` should be set to True # otherwise, we will generate an auth header if include_client_id is not True: client_id = self.client_id if client_id: log.debug( 'Encoding `client_id` "%s" with `client_secret` ' "as Basic auth credentials.", client_id, ) client_secret = client_secret if client_secret is not None else "" auth = aiohttp.BasicAuth(login=client_id, password=client_secret) if include_client_id: # this was pulled out of the params # it needs to be passed into prepare_request_body if client_secret is not None: kwargs["client_secret"] = client_secret body = self._client.prepare_request_body( code=code, body=body, redirect_uri=self.redirect_uri, include_client_id=include_client_id, **kwargs) headers = headers or { "Accept": "application/json", "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8", } self.token = {} request_kwargs = {} if method.upper() == "POST": request_kwargs["params" if force_querystring else "data"] = dict( urldecode(body)) elif method.upper() == "GET": request_kwargs["params"] = dict(urldecode(body)) else: raise ValueError("The method kwarg must be POST or GET.") async with self.request(method=method, url=token_url, timeout=timeout, headers=headers, auth=auth, verify_ssl=verify_ssl, proxy=proxies, **request_kwargs) as resp: log.debug("Request to fetch token completed with status %s.", resp.status) log.debug("Request headers were %s", headers) log.debug("Request body was %s", body) text = await resp.text() log.debug("Response headers were %s and content %s.", resp.headers, text) (resp, ) = self._invoke_hooks("access_token_response", resp) self._client.parse_request_body_response(text, scope=self.scope) self.token = self._client.token log.debug("Obtained token %s.", self.token) return self.token
def fetch_token(self, token_url, code=None, authorization_response=None, body='', auth=None, username=None, password=None, method='POST', timeout=None, headers=None, verify=True, proxies=None, **kwargs): """Generic method for fetching an access token from the token endpoint. If you are using the MobileApplicationClient you will want to use token_from_fragment instead of fetch_token. :param token_url: Token endpoint URL, must use HTTPS. :param code: Authorization code (used by WebApplicationClients). :param authorization_response: Authorization response URL, the callback URL of the request back to you. Used by WebApplicationClients instead of code. :param body: Optional application/x-www-form-urlencoded body to add the include in the token request. Prefer kwargs over body. :param auth: An auth tuple or method as accepted by requests. :param username: Username used by LegacyApplicationClients. :param password: Password used by LegacyApplicationClients. :param method: The HTTP method used to make the request. Defaults to POST, but may also be GET. Other methods should be added as needed. :param headers: Dict to default request headers with. :param timeout: Timeout of the request in seconds. :param verify: Verify SSL certificate. :param kwargs: Extra parameters to include in the token request. :return: A token dict """ if not is_secure_transport(token_url): raise InsecureTransportError() if not code and authorization_response: self._client.parse_request_uri_response(authorization_response, state=self._state) code = self._client.code elif not code and isinstance(self._client, WebApplicationClient): code = self._client.code if not code: raise ValueError('Please supply either code or ' 'authorization_response parameters.') body = self._client.prepare_request_body(code=code, body=body, redirect_uri=self.redirect_uri, username=username, password=password, **kwargs) client_id = kwargs.get('client_id', '') if auth is None: if client_id: log.debug('Encoding client_id "%s" with client_secret as Basic auth credentials.', client_id) client_secret = kwargs.get('client_secret', '') client_secret = client_secret if client_secret is not None else '' auth = requests.auth.HTTPBasicAuth(client_id, client_secret) elif username: if password is None: raise ValueError('Username was supplied, but not password.') log.debug('Encoding username, password as Basic auth credentials.') auth = requests.auth.HTTPBasicAuth(username, password) headers = headers or { 'Accept': 'application/json', 'Content-Type': 'application/json', } self.token = {} if method.upper() == 'POST': r = self.post(token_url, json=dict(urldecode(body)), timeout=timeout, headers=headers, auth=auth, verify=verify, proxies=proxies) log.debug('Prepared fetch token request body %s', body) elif method.upper() == 'GET': # if method is not 'POST', switch body to querystring and GET r = self.get(token_url, params=dict(urldecode(body)), timeout=timeout, headers=headers, auth=auth, verify=verify, proxies=proxies) log.debug('Prepared fetch token request querystring %s', body) else: raise ValueError('The method kwarg must be POST or GET.') log.debug('Request to fetch token completed with status %s.', r.status_code) log.debug('Request headers were %s', r.request.headers) log.debug('Request body was %s', r.request.body) log.debug('Response headers were %s and content %s.', r.headers, r.text) log.debug('Invoking %d token response hooks.', len(self.compliance_hook['access_token_response'])) for hook in self.compliance_hook['access_token_response']: log.debug('Invoking hook %s.', hook) r = hook(r) self._client.parse_request_body_response(r.text, scope=self.scope) self.token = self._client.token log.debug('Obtained token %s.', self.token) return self.token
async def fetch_token( self, token_url, code=None, authorization_response=None, body="", auth=None, username=None, password=None, method="POST", timeout=None, headers=None, verify_ssl=True, proxy=None, **kwargs, ): """Generic method for fetching an access token from the token endpoint. If you are using the MobileApplicationClient you will want to use token_from_fragment instead of fetch_token. :param token_url: Token endpoint URL, must use HTTPS. :param code: Authorization code (used by WebApplicationClients). :param authorization_response: Authorization response URL, the callback URL of the request back to you. Used by WebApplicationClients instead of code. :param body: Optional application/x-www-form-urlencoded body to add the include in the token request. Prefer kwargs over body. :param auth: An auth tuple or method as accepted by aiohttp. :param username: Username used by LegacyApplicationClients. :param password: Password used by LegacyApplicationClients. :param method: The HTTP method used to make the request. Defaults to POST, but may also be GET. Other methods should be added as needed. :param headers: Dict to default request headers with. :param timeout: Timeout of the request in seconds. :param verify_ssl: Verify SSL certificate. :param kwargs: Extra parameters to include in the token request. :return: A token dict """ if not is_secure_transport(token_url): raise InsecureTransportError() if not code and authorization_response: self._client.parse_request_uri_response(authorization_response, state=self._state) code = self._client.code elif not code and isinstance(self._client, WebApplicationClient): code = self._client.code if not code: raise ValueError("Please supply either code or " "authorization_response parameters.") body = self._client.prepare_request_body( code=code, body=body, redirect_uri=self.redirect_uri, username=username, password=password, **kwargs, ) client_id = kwargs.get("client_id", "") if auth is None: if client_id: log.debug( 'Encoding client_id "%s" with client_secret as Basic auth credentials.', client_id, ) client_secret = kwargs.get("client_secret", "") client_secret = client_secret if client_secret is not None else "" auth = aiohttp.BasicAuth(client_id, client_secret) elif username: if password is None: raise ValueError( "Username was supplied, but not password.") log.debug( "Encoding username, password as Basic auth credentials.") auth = aiohttp.BasicAuth(username, password) headers = headers or { "Accept": "application/json", "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8", } self.token = {} if method.upper() == "POST": req = self.post( token_url, data=dict(urldecode(body)), timeout=timeout, headers=headers, auth=auth, verify_ssl=verify_ssl, proxy=proxy, ) log.debug("Prepared fetch token request body %s", body) elif method.upper() == "GET": # if method is not 'POST', switch body to querystring and GET req = self.get( token_url, params=dict(urldecode(body)), timeout=timeout, headers=headers, auth=auth, verify_ssl=verify_ssl, proxy=proxy, ) log.debug("Prepared fetch token request querystring %s", body) else: raise ValueError("The method kwarg must be POST or GET.") async with req as resp: text = await resp.text() log.debug("Request to fetch token completed with status %s.", resp.status) log.debug("Request headers were %s", resp.request_info.headers) log.debug("Response headers were %s and content %s.", resp.headers, text) log.debug( "Invoking %s token response hooks.", len(self.compliance_hook["access_token_response"]), ) for hook in self.compliance_hook["access_token_response"]: log.debug("Invoking hook %s.", hook) resp = hook(resp) self._client.parse_request_body_response(text, scope=self.scope) self.token = self._client.token log.debug("Obtained token %s.", self.token) return self.token
def refresh_token(self, token_url, refresh_token=None, body='', auth=None, timeout=None, headers=None, verify=True, proxies=None, **kwargs): """Fetch a new access token using a refresh token. :param token_url: The token endpoint, must be HTTPS. :param refresh_token: The refresh_token to use. :param body: Optional application/x-www-form-urlencoded body to add the include in the token request. Prefer kwargs over body. :param auth: An auth tuple or method as accepted by requests. :param timeout: Timeout of the request in seconds. :param verify: Verify SSL certificate. :param kwargs: Extra parameters to include in the token request. :return: A token dict """ if not token_url: raise ValueError('No token endpoint set for auto_refresh.') if not is_secure_transport(token_url): raise InsecureTransportError() refresh_token = refresh_token or self.token.get('refresh_token') log.debug('Adding auto refresh key word arguments %s.', self.auto_refresh_kwargs) kwargs.update(self.auto_refresh_kwargs) auth = auth or kwargs.get('auth') client_id = kwargs.get('client_id') client_secret = kwargs.get('client_secret', '') if client_id and (auth is None): log.debug( 'Encoding client_id "%s" with client_secret as Basic auth credentials.', client_id) auth = requests.auth.HTTPBasicAuth(client_id, client_secret) body = self._client.prepare_refresh_body(body=body, refresh_token=refresh_token, scope=self.scope, **kwargs) log.debug('Prepared refresh token request body %s', body) if headers is None: headers = { 'Accept': 'application/json', 'Content-Type': ('application/x-www-form-urlencoded;charset=UTF-8'), } r = self.post(token_url, data=dict(urldecode(body)), auth=auth, timeout=timeout, headers=headers, verify=verify, withhold_token=True, proxies=proxies) log.debug('Request to refresh token completed with status %s.', r.status_code) log.debug('Response headers were %s and content %s.', r.headers, r.text) log.debug('Invoking %d token response hooks.', len(self.compliance_hook['refresh_token_response'])) for hook in self.compliance_hook['refresh_token_response']: log.debug('Invoking hook %s.', hook) r = hook(r) self.token = self._client.parse_request_body_response(r.text, scope=self.scope) if not 'refresh_token' in self.token: log.debug('No new refresh token given. Re-using old.') self.token['refresh_token'] = refresh_token return self.token
def request(self, method, url, data=None, headers=None, withhold_token=False, client_id=None, client_secret=None, files=None, **kwargs): """Intercept all requests and add the OAuth 2 token if present.""" if not is_secure_transport(url): raise InsecureTransportError() if self.token and not withhold_token: log.debug( "Invoking %d protected resource request hooks.", len(self.compliance_hook["protected_request"]), ) for hook in self.compliance_hook["protected_request"]: log.debug("Invoking hook %s.", hook) url, headers, data = hook(url, headers, data) log.debug("Adding token %s to request.", self.token) try: url, headers, data = self._client.add_token(url, http_method=method, body=data, headers=headers) # Attempt to retrieve and save new access token if expired except TokenExpiredError: if self.auto_refresh_url: log.debug( "Auto refresh is set, attempting to refresh at %s.", self.auto_refresh_url, ) # We mustn't pass auth twice. auth = kwargs.pop("auth", None) if client_id and client_secret and (auth is None): log.debug( 'Encoding client_id "%s" with client_secret as Basic auth credentials.', client_id, ) auth = requests.auth.HTTPBasicAuth( client_id, client_secret) token = self.refresh_token(self.auto_refresh_url, auth=auth, **kwargs) if self.token_updater: log.debug("Updating token to %s using %s.", token, self.token_updater) self.token_updater(token) url, headers, data = self._client.add_token( url, http_method=method, body=data, headers=headers) else: raise TokenUpdated(token) else: raise log.debug("Requesting url %s using method %s.", url, method) log.debug("Supplying headers %s and data %s", headers, data) log.debug("Passing through key word arguments %s.", kwargs) return super(OAuth2Session, self).request(method, url, headers=headers, data=data, files=files, **kwargs)
async def refresh_token(self, token_url, refresh_token=None, body="", auth=None, timeout=None, headers=None, verify_ssl=True, proxies=None, **kwargs): """Fetch a new access token using a refresh token. :param token_url: The token endpoint, must be HTTPS. :param refresh_token: The refresh_token to use. :param body: Optional application/x-www-form-urlencoded body to add the include in the token request. Prefer kwargs over body. :param auth: An auth tuple or method as accepted by `requests`. :param timeout: Timeout of the request in seconds. :param headers: A dict of headers to be used by `requests`. :param verify: Verify SSL certificate. :param proxies: The `proxies` argument will be passed to `requests`. :param kwargs: Extra parameters to include in the token request. :return: A token dict """ if not token_url: raise ValueError("No token endpoint set for auto_refresh.") if not is_secure_transport(token_url): raise InsecureTransportError() refresh_token = refresh_token or self.token.get("refresh_token") log.debug("Adding auto refresh key word arguments %s.", self.auto_refresh_kwargs) kwargs.update(self.auto_refresh_kwargs) body = self._client.prepare_refresh_body(body=body, refresh_token=refresh_token, scope=self.scope, **kwargs) log.debug("Prepared refresh token request body %s", body) if headers is None: headers = { "Accept": "application/json", "Content-Type": ("application/x-www-form-urlencoded;charset=UTF-8"), } async with self.post( token_url, data=dict(urldecode(body)), auth=auth, timeout=timeout, headers=headers, verify_ssl=verify_ssl, withhold_token=True, # proxy=proxies, ) as resp: log.debug("Request to refresh token completed with status %s.", resp.status) text = await resp.text() log.debug("Response headers were %s and content %s.", resp.headers, text) (resp, ) = self._invoke_hooks("refresh_token_response", resp) self.token = self._client.parse_request_body_response(text, scope=self.scope) if "refresh_token" not in self.token: log.debug("No new refresh token given. Re-using old.") self.token["refresh_token"] = refresh_token return self.token
def fetch_token( self, token_url, code=None, authorization_response=None, body="", auth=None, username=None, password=None, method="POST", timeout=None, headers=None, verify=True, proxies=None, include_client_id=None, client_secret=None, **kwargs ): """Generic method for fetching an access token from the token endpoint. If you are using the MobileApplicationClient you will want to use `token_from_fragment` instead of `fetch_token`. The current implementation enforces the RFC guidelines. :param token_url: Token endpoint URL, must use HTTPS. :param code: Authorization code (used by WebApplicationClients). :param authorization_response: Authorization response URL, the callback URL of the request back to you. Used by WebApplicationClients instead of code. :param body: Optional application/x-www-form-urlencoded body to add the include in the token request. Prefer kwargs over body. :param auth: An auth tuple or method as accepted by `requests`. :param username: Username required by LegacyApplicationClients to appear in the request body. :param password: Password required by LegacyApplicationClients to appear in the request body. :param method: The HTTP method used to make the request. Defaults to POST, but may also be GET. Other methods should be added as needed. :param timeout: Timeout of the request in seconds. :param headers: Dict to default request headers with. :param verify: Verify SSL certificate. :param proxies: The `proxies` argument is passed onto `requests`. :param include_client_id: Should the request body include the `client_id` parameter. Default is `None`, which will attempt to autodetect. This can be forced to always include (True) or never include (False). :param client_secret: The `client_secret` paired to the `client_id`. This is generally required unless provided in the `auth` tuple. If the value is `None`, it will be omitted from the request, however if the value is an empty string, an empty string will be sent. :param kwargs: Extra parameters to include in the token request. :return: A token dict """ if not is_secure_transport(token_url): raise InsecureTransportError() if not code and authorization_response: self._client.parse_request_uri_response( authorization_response, state=self._state ) code = self._client.code elif not code and isinstance(self._client, WebApplicationClient): code = self._client.code if not code: raise ValueError( "Please supply either code or " "authorization_response parameters." ) # Earlier versions of this library build an HTTPBasicAuth header out of # `username` and `password`. The RFC states, however these attributes # must be in the request body and not the header. # If an upstream server is not spec compliant and requires them to # appear as an Authorization header, supply an explicit `auth` header # to this function. # This check will allow for empty strings, but not `None`. # # Refernences # 4.3.2 - Resource Owner Password Credentials Grant # https://tools.ietf.org/html/rfc6749#section-4.3.2 if isinstance(self._client, LegacyApplicationClient): if username is None: raise ValueError( "`LegacyApplicationClient` requires both the " "`username` and `password` parameters." ) if password is None: raise ValueError( "The required paramter `username` was supplied, " "but `password` was not." ) # merge username and password into kwargs for `prepare_request_body` if username is not None: kwargs["username"] = username if password is not None: kwargs["password"] = password # is an auth explicitly supplied? if auth is not None: # if we're dealing with the default of `include_client_id` (None): # we will assume the `auth` argument is for an RFC compliant server # and we should not send the `client_id` in the body. # This approach allows us to still force the client_id by submitting # `include_client_id=True` along with an `auth` object. if include_client_id is None: include_client_id = False # otherwise we may need to create an auth header else: # since we don't have an auth header, we MAY need to create one # it is possible that we want to send the `client_id` in the body # if so, `include_client_id` should be set to True # otherwise, we will generate an auth header if include_client_id is not True: client_id = self.client_id if client_id: log.debug( 'Encoding `client_id` "%s" with `client_secret` ' "as Basic auth credentials.", client_id, ) client_secret = client_secret if client_secret is not None else "" auth = requests.auth.HTTPBasicAuth(client_id, client_secret) if include_client_id: # this was pulled out of the params # it needs to be passed into prepare_request_body if client_secret is not None: kwargs["client_secret"] = client_secret body = self._client.prepare_request_body( code=code, body=body, redirect_uri=self.redirect_uri, include_client_id=include_client_id, **kwargs ) headers = headers or { "Accept": "application/json", "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8", } self.token = {} if method.upper() == "POST": r = self.post( token_url, data=dict(urldecode(body)), timeout=timeout, headers=headers, auth=auth, verify=verify, proxies=proxies, ) log.debug("Prepared fetch token request body %s", body) elif method.upper() == "GET": # if method is not 'POST', switch body to querystring and GET r = self.get( token_url, params=dict(urldecode(body)), timeout=timeout, headers=headers, auth=auth, verify=verify, proxies=proxies, ) log.debug("Prepared fetch token request querystring %s", body) else: raise ValueError("The method kwarg must be POST or GET.") log.debug("Request to fetch token completed with status %s.", r.status_code) log.debug("Request headers were %s", r.request.headers) log.debug("Request body was %s", r.request.body) log.debug("Response headers were %s and content %s.", r.headers, r.text) log.debug( "Invoking %d token response hooks.", len(self.compliance_hook["access_token_response"]), ) for hook in self.compliance_hook["access_token_response"]: log.debug("Invoking hook %s.", hook) r = hook(r) self._client.parse_request_body_response(r.text, scope=self.scope) self.token = self._client.token log.debug("Obtained token %s.", self.token) return self.token
async def refresh_token(self, token_url, refresh_token=None, body='', auth=None, timeout=None, headers=None, proxy=None, **kwargs): """Fetch a new access token using a refresh token. :param token_url: The token endpoint, must be HTTPS. :param refresh_token: The refresh_token to use. :param body: Optional application/x-www-form-urlencoded body to add the include in the token request. Prefer kwargs over body. :param auth: An auth tuple or method as accepted by `requests`. :param timeout: Timeout of the request in seconds. :param headers: A dict of headers to be used by `requests`. :param proxy: The `proxy` argument will be passed to `requests`. :param kwargs: Extra parameters to include in the token request. :return: A token dict """ if not token_url: raise ValueError('No token endpoint set for auto_refresh.') if not is_secure_transport(token_url): raise InsecureTransportError() refresh_token = refresh_token or self.token.get('refresh_token') log.debug('Adding auto refresh key word arguments %s.', self.auto_refresh_kwargs) kwargs.update(self.auto_refresh_kwargs) body = self._client.prepare_refresh_body(body=body, refresh_token=refresh_token, scope=self.scope, **kwargs) log.debug('Prepared refresh token request body %s', body) if headers is None: headers = { 'Accept': 'application/json', 'Content-Type': ('application/x-www-form-urlencoded;charset=UTF-8'), } r = await self.request("POST", token_url, data=dict(urldecode(body)), auth=auth, timeout=timeout, headers=headers, withhold_token=True, proxy=proxy) log.debug('Request to refresh token completed with status %s.', r.status) log.debug('Response headers were %s and content %s.', r.headers, await r.text()) log.debug('Invoking %d token response hooks.', len(self.compliance_hook['refresh_token_response'])) for hook in self.compliance_hook['refresh_token_response']: log.debug('Invoking hook %s.', hook) r = hook(r) self.token = self._client.parse_request_body_response(await r.text(), scope=self.scope) if 'refresh_token' not in self.token: log.debug('No new refresh token given. Re-using old.') self.token['refresh_token'] = refresh_token return self.token
def request(self, method, url, data=None, headers=None, withhold_token=False, client_id=None, client_secret=None, **kwargs): """Intercept all requests and add the OAuth 2 token if present.""" if not is_secure_transport(url): raise InsecureTransportError() if self.token and not withhold_token: log.debug('Invoking %d protected resource request hooks.', len(self.compliance_hook['protected_request'])) for hook in self.compliance_hook['protected_request']: log.debug('Invoking hook %s.', hook) url, headers, data = hook(url, headers, data) log.debug('Adding token %s to request.', self.token) try: url, headers, data = self._client.add_token(url, http_method=method, body=data, headers=headers) # Attempt to retrieve and save new access token if expired except TokenExpiredError: if self.auto_refresh_url: log.debug( 'Auto refresh is set, attempting to refresh at %s.', self.auto_refresh_url) # Someday this code can be eliminated, we should be able to # simply pass **self.auto_refresh_kwargs to # `refresh_token()` what follows is to maintain # compatibility # Start with kwargs explicitly requested for refresh. refresh_kwargs = self.auto_refresh_kwargs.copy() if kwargs.get('auth', None): # If user supplied `auth` to `request()` warn them to # instead use `auto_refresh_kwargs`. But honor their # intent for now. warnings.warn('auth argument supplied. Please specify ' 'token refresh authentication in ' 'auto_refresh_kwargs.') refresh_kwargs['auth'] = kwargs.pop('auth') elif client_id: # If no auth was provided, but `client_id` and # `client_secret` were, warn the user and create an # HTTP Basic auth header. It is preferred if the user # instead place an auth param into `auto_refresh_kwargs` warnings.warn('client_id argument supplied, Please ' 'specify token refresh authentication in' 'auto_refresh_kwargs') log.debug( 'Encoding client_id "%s" with client_secret as Basic auth credentials.', client_id) if not client_secret: warnings.warn('client_id provided, but ' 'client_secret missing') client_secret = '' refresh_kwargs['auth'] = \ requests.auth.HTTPBasicAuth(client_id, client_secret) # End of compat. code. token = self.refresh_token(self.auto_refresh_url, **refresh_kwargs) if self.token_updater: log.debug('Updating token to %s using %s.', token, self.token_updater) self.token_updater(token) url, headers, data = self._client.add_token( url, http_method=method, body=data, headers=headers) else: raise TokenUpdated(token) else: raise log.debug('Requesting url %s using method %s.', url, method) log.debug('Supplying headers %s and data %s', headers, data) log.debug('Passing through key word arguments %s.', kwargs) return super(OAuth2Session, self).request(method, url, headers=headers, data=data, **kwargs)
async def _request(self, method, url, *, data=None, headers=None, withhold_token=False, client_id=None, client_secret=None, **kwargs): """Intercept all requests and add the OAuth 2 token if present.""" if not is_secure_transport(url): raise InsecureTransportError() if self.token and not withhold_token: url, headers, data = self._invoke_hooks("protected_request", url, headers, data) log.debug("Adding token %s to request.", self.token) try: url, headers, data = self._client.add_token(url, http_method=method, body=data, headers=headers) # Attempt to retrieve and save new access token if expired except TokenExpiredError: if self.auto_refresh_url: log.debug( "Auto refresh is set, attempting to refresh at %s.", self.auto_refresh_url, ) # We mustn't pass auth twice. auth = kwargs.pop("auth", None) if client_id and client_secret and (auth is None): log.debug( 'Encoding client_id "%s" with client_secret as Basic auth credentials.', client_id, ) auth = aiohttp.BasicAuth(login=client_id, password=client_secret) token = await self.refresh_token(self.auto_refresh_url, auth=auth, **kwargs) if self.token_updater: log.debug("Updating token to %s using %s.", token, self.token_updater) await self.token_updater(token) url, headers, data = self._client.add_token( url, http_method=method, body=data, headers=headers) else: raise TokenUpdated(token) else: raise log.debug("Requesting url %s using method %s.", url, method) log.debug("Supplying headers %s and data %s", headers, data) log.debug("Passing through key word arguments %s.", kwargs) return await super()._request(method, url, headers=headers, data=data, **kwargs)
def fetch_token(self, token_url, code=None, authorization_response=None, body='', auth=None, username=None, password=None, method='POST', timeout=None, headers=None, verify=True, proxies=None, include_client_id=None, client_secret=None, **kwargs): """Generic method for fetching an access token from the token endpoint. If you are using the MobileApplicationClient you will want to use `token_from_fragment` instead of `fetch_token`. The current implementation enforces the RFC guidelines. :param token_url: Token endpoint URL, must use HTTPS. :param code: Authorization code (used by WebApplicationClients). :param authorization_response: Authorization response URL, the callback URL of the request back to you. Used by WebApplicationClients instead of code. :param body: Optional application/x-www-form-urlencoded body to add the include in the token request. Prefer kwargs over body. :param auth: An auth tuple or method as accepted by `requests`. :param username: Username required by LegacyApplicationClients to appear in the request body. :param password: Password required by LegacyApplicationClients to appear in the request body. :param method: The HTTP method used to make the request. Defaults to POST, but may also be GET. Other methods should be added as needed. :param timeout: Timeout of the request in seconds. :param headers: Dict to default request headers with. :param verify: Verify SSL certificate. :param proxies: The `proxies` argument is passed onto `requests`. :param include_client_id: Should the request body include the `client_id` parameter. Default is `None`, which will attempt to autodetect. This can be forced to always include (True) or never include (False). :param client_secret: The `client_secret` paired to the `client_id`. This is generally required unless provided in the `auth` tuple. If the value is `None`, it will be omitted from the request, however if the value is an empty string, an empty string will be sent. :param kwargs: Extra parameters to include in the token request. :return: A token dict """ if not is_secure_transport(token_url): raise InsecureTransportError() if not code and authorization_response: self._client.parse_request_uri_response(authorization_response, state=self._state) code = self._client.code elif not code and isinstance(self._client, WebApplicationClient): code = self._client.code if not code: raise ValueError('Please supply either code or ' 'authorization_response parameters.') # Earlier versions of this library build an HTTPBasicAuth header out of # `username` and `password`. The RFC states, however these attributes # must be in the request body and not the header. # If an upstream server is not spec compliant and requires them to # appear as an Authorization header, supply an explicit `auth` header # to this function. # This check will allow for empty strings, but not `None`. # # Refernences # 4.3.2 - Resource Owner Password Credentials Grant # https://tools.ietf.org/html/rfc6749#section-4.3.2 if isinstance(self._client, LegacyApplicationClient): if username is None: raise ValueError('`LegacyApplicationClient` requires both the ' '`username` and `password` parameters.') if password is None: raise ValueError('The required paramter `username` was supplied, ' 'but `password` was not.') # merge username and password into kwargs for `prepare_request_body` if username is not None: kwargs['username'] = username if password is not None: kwargs['password'] = password # is an auth explicitly supplied? if auth is not None: # if we're dealing with the default of `include_client_id` (None): # we will assume the `auth` argument is for an RFC compliant server # and we should not send the `client_id` in the body. # This approach allows us to still force the client_id by submitting # `include_client_id=True` along with an `auth` object. if include_client_id is None: include_client_id = False # otherwise we may need to create an auth header else: # since we don't have an auth header, we MAY need to create one # it is possible that we want to send the `client_id` in the body # if so, `include_client_id` should be set to True # otherwise, we will generate an auth header if include_client_id is not True: client_id = self.client_id if client_id: log.debug('Encoding `client_id` "%s" with `client_secret` ' 'as Basic auth credentials.', client_id) client_secret = client_secret if client_secret is not None else '' auth = requests.auth.HTTPBasicAuth(client_id, client_secret) if include_client_id: # this was pulled out of the params # it needs to be passed into prepare_request_body if client_secret is not None: kwargs['client_secret'] = client_secret body = self._client.prepare_request_body(code=code, body=body, redirect_uri=self.redirect_uri, include_client_id=include_client_id, **kwargs) headers = headers or { 'Accept': 'application/json', 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8', } self.token = {} if method.upper() == 'POST': r = self.post(token_url, data=dict(urldecode(body)), timeout=timeout, headers=headers, auth=auth, verify=verify, proxies=proxies) log.debug('Prepared fetch token request body %s', body) elif method.upper() == 'GET': # if method is not 'POST', switch body to querystring and GET r = self.get(token_url, params=dict(urldecode(body)), timeout=timeout, headers=headers, auth=auth, verify=verify, proxies=proxies) log.debug('Prepared fetch token request querystring %s', body) else: raise ValueError('The method kwarg must be POST or GET.') log.debug('Request to fetch token completed with status %s.', r.status_code) log.debug('Request headers were %s', r.request.headers) log.debug('Request body was %s', r.request.body) log.debug('Response headers were %s and content %s.', r.headers, r.text) log.debug('Invoking %d token response hooks.', len(self.compliance_hook['access_token_response'])) for hook in self.compliance_hook['access_token_response']: log.debug('Invoking hook %s.', hook) r = hook(r) self._client.parse_request_body_response(r.text, scope=self.scope) self.token = self._client.token log.debug('Obtained token %s.', self.token) return self.token
def fetch_token(self, token_url, code=None, authorization_response=None, body='', auth=None, username=None, password=None, method='POST', timeout=None, headers=None, verify=True, **kwargs): """Generic method for fetching an access token from the token endpoint. If you are using the MobileApplicationClient you will want to use token_from_fragment instead of fetch_token. :param token_url: Token endpoint URL, must use HTTPS. :param code: Authorization code (used by WebApplicationClients). :param authorization_response: Authorization response URL, the callback URL of the request back to you. Used by WebApplicationClients instead of code. :param body: Optional application/x-www-form-urlencoded body to add the include in the token request. Prefer kwargs over body. :param auth: An auth tuple or method as accepted by requests. :param username: Username used by LegacyApplicationClients. :param password: Password used by LegacyApplicationClients. :param method: The HTTP method used to make the request. Defaults to POST, but may also be GET. Other methods should be added as needed. :param headers: Dict to default request headers with. :param timeout: Timeout of the request in seconds. :param verify: Verify SSL certificate. :param kwargs: Extra parameters to include in the token request. :return: A token dict """ if not is_secure_transport(token_url): raise InsecureTransportError() if not code and authorization_response: self._client.parse_request_uri_response(authorization_response, state=self._state) code = self._client.code elif not code and isinstance(self._client, WebApplicationClient): code = self._client.code if not code: raise ValueError('Please supply either code or ' 'authorization_code parameters.') body = self._client.prepare_request_body(code=code, body=body, redirect_uri=self.redirect_uri, username=username, password=password, **kwargs) headers = headers or { 'Accept': 'application/json', 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8', } if method.upper() == 'POST': r = self.post(token_url, data=dict(urldecode(body)), timeout=timeout, headers=headers, auth=auth, verify=verify) log.debug('Prepared fetch token request body %s', body) elif method.upper() == 'GET': # if method is not 'POST', switch body to querystring and GET r = self.get(token_url, params=dict(urldecode(body)), timeout=timeout, headers=headers, auth=auth, verify=verify) log.debug('Prepared fetch token request querystring %s', body) else: raise ValueError('The method kwarg must be POST or GET.') log.debug('Request to fetch token completed with status %s.', r.status_code) log.debug('Request headers were %s', r.request.headers) log.debug('Request body was %s', r.request.body) log.debug('Response headers were %s and content %s.', r.headers, r.text) log.debug('Invoking %d token response hooks.', len(self.compliance_hook['access_token_response'])) for hook in self.compliance_hook['access_token_response']: log.debug('Invoking hook %s.', hook) r = hook(r) r.raise_for_status() self._client.parse_request_body_response(r.text, scope=self.scope) self.token = self._client.token log.debug('Obtained token %s.', self.token) return self.token
def fetch_token( self, token_url, code=None, authorization_response=None, body="", auth=None, username=None, password=None, method="POST", timeout=None, headers=None, verify=True, proxies=None, **kwargs ): """Generic method for fetching an access token from the token endpoint. If you are using the MobileApplicationClient you will want to use token_from_fragment instead of fetch_token. :param token_url: Token endpoint URL, must use HTTPS. :param code: Authorization code (used by WebApplicationClients). :param authorization_response: Authorization response URL, the callback URL of the request back to you. Used by WebApplicationClients instead of code. :param body: Optional application/x-www-form-urlencoded body to add the include in the token request. Prefer kwargs over body. :param auth: An auth tuple or method as accepted by requests. :param username: Username used by LegacyApplicationClients. :param password: Password used by LegacyApplicationClients. :param method: The HTTP method used to make the request. Defaults to POST, but may also be GET. Other methods should be added as needed. :param headers: Dict to default request headers with. :param timeout: Timeout of the request in seconds. :param verify: Verify SSL certificate. :param kwargs: Extra parameters to include in the token request. :return: A token dict """ if not is_secure_transport(token_url): raise InsecureTransportError() if not code and authorization_response: self._client.parse_request_uri_response(authorization_response, state=self._state) code = self._client.code elif not code and isinstance(self._client, WebApplicationClient): code = self._client.code if not code: raise ValueError("Please supply either code or " "authorization_response parameters.") body = self._client.prepare_request_body( code=code, body=body, redirect_uri=self.redirect_uri, username=username, password=password, **kwargs ) client_id = kwargs.get("client_id", "") if auth is None: if client_id: log.debug('Encoding client_id "%s" with client_secret as Basic auth credentials.', client_id) client_secret = kwargs.get("client_secret", "") client_secret = client_secret if client_secret is not None else "" auth = requests.auth.HTTPBasicAuth(client_id, client_secret) elif username: if password is None: raise ValueError("Username was supplied, but not password.") log.debug("Encoding username, password as Basic auth credentials.") auth = requests.auth.HTTPBasicAuth(username, password) headers = headers or { "Accept": "application/json", "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8", } self.token = {} if method.upper() == "POST": r = self.post( token_url, data=dict(urldecode(body)), timeout=timeout, headers=headers, auth=auth, verify=verify, proxies=proxies, ) log.debug("Prepared fetch token request body %s", body) elif method.upper() == "GET": # if method is not 'POST', switch body to querystring and GET r = self.get( token_url, params=dict(urldecode(body)), timeout=timeout, headers=headers, auth=auth, verify=verify, proxies=proxies, ) log.debug("Prepared fetch token request querystring %s", body) else: raise ValueError("The method kwarg must be POST or GET.") log.debug("Request to fetch token completed with status %s.", r.status_code) log.debug("Request headers were %s", r.request.headers) log.debug("Request body was %s", r.request.body) log.debug("Response headers were %s and content %s.", r.headers, r.text) log.debug("Invoking %d token response hooks.", len(self.compliance_hook["access_token_response"])) for hook in self.compliance_hook["access_token_response"]: log.debug("Invoking hook %s.", hook) r = hook(r) self._client.parse_request_body_response(r.text, scope=self.scope) self.token = self._client.token log.debug("Obtained token %s.", self.token) return self.token