diff --git a/requests_oauthlib/compliance_fixes/__init__.py b/requests_oauthlib/compliance_fixes/__init__.py index 8815ea0..ee4378e 100644 --- a/requests_oauthlib/compliance_fixes/__init__.py +++ b/requests_oauthlib/compliance_fixes/__init__.py @@ -7,3 +7,4 @@ from .weibo import weibo_compliance_fix from .plentymarkets import plentymarkets_compliance_fix from .ebay import ebay_compliance_fix +from .wix import wix_compliance_fix diff --git a/requests_oauthlib/compliance_fixes/wix.py b/requests_oauthlib/compliance_fixes/wix.py new file mode 100644 index 0000000..121a56b --- /dev/null +++ b/requests_oauthlib/compliance_fixes/wix.py @@ -0,0 +1,36 @@ +import json +from oauthlib.common import urldecode + +""" +Wix requires the request body for token requests to be sent in JSON format +instead of x-www-form-urlencoded. +""" +def wix_compliance_fix(session): + + def _non_compliant_access_token_request_body( + url: str, headers: dict, request_kwargs: dict + ): + """ + Move the request body from the `data` kwarg to the `json` kwarg, + and set the `Content-Type` header to `application/json`. + """ + headers["Content-Type"] = "application/json" + request_kwargs["json"] = request_kwargs["data"] + del request_kwargs["data"] + return url, headers, request_kwargs + + def _non_compliant_refresh_token_request_body( + token_url: str, headers: dict, body: str + ): + """ + Convert the body from a urlencoded string to a JSON string, + and set the `Content-Type` header to `application/json`. + """ + headers["Content-Type"] = "application/json" + body = json.dumps(dict(urldecode(body))) + return token_url, headers, body + + session.register_compliance_hook("access_token_request", _non_compliant_access_token_request_body) + session.register_compliance_hook("refresh_token_request", _non_compliant_refresh_token_request_body) + + return session diff --git a/requests_oauthlib/oauth2_session.py b/requests_oauthlib/oauth2_session.py index 93cc4d7..05ae35d 100644 --- a/requests_oauthlib/oauth2_session.py +++ b/requests_oauthlib/oauth2_session.py @@ -473,9 +473,12 @@ def refresh_token( log.debug("Invoking refresh_token_request hook %s.", hook) token_url, headers, body = hook(token_url, headers, body) + if headers['Content-Type'] == "application/x-www-form-urlencoded": + body = dict(urldecode(body)) + r = self.post( token_url, - data=dict(urldecode(body)), + data=body, auth=auth, timeout=timeout, headers=headers, diff --git a/tests/test_compliance_fixes.py b/tests/test_compliance_fixes.py index c5166bd..3892136 100644 --- a/tests/test_compliance_fixes.py +++ b/tests/test_compliance_fixes.py @@ -16,6 +16,7 @@ from requests_oauthlib.compliance_fixes import instagram_compliance_fix from requests_oauthlib.compliance_fixes import plentymarkets_compliance_fix from requests_oauthlib.compliance_fixes import ebay_compliance_fix +from requests_oauthlib.compliance_fixes.wix import wix_compliance_fix class FacebookComplianceFixTest(TestCase): @@ -385,3 +386,46 @@ def test_refresh_token(self): "https://example.com/refresh", ) assert token["token_type"] == "Bearer" + + +class WixComplianceFixTest(TestCase): + + def setUp(self): + wix = OAuth2Session() + self.session = wix_compliance_fix(wix) + + def test_access_token_request_sent_as_json(self): + mocker = requests_mock.Mocker() + mocker.post( + "https://www.wixapis.com/oauth/access", + request_headers={"Content-Type": "application/json"}, + json={"access_token": "sample_access_token", "refresh_token": "sample_refresh_token"}, + additional_matcher=lambda req: req.json() == {'grant_type': 'authorization_code', 'code': 'sample_code'} + ) + mocker.start() + self.addCleanup(mocker.stop) + + token = self.session.fetch_token( + "https://www.wixapis.com/oauth/access", + code="sample_code" + ) + + self.assertEqual(token, {"access_token": "sample_access_token", "refresh_token": "sample_refresh_token"}) + + def test_refresh_token_request_sent_as_json(self): + mocker = requests_mock.Mocker() + mocker.post( + "https://www.wixapis.com/oauth/access", + request_headers={"Content-Type": "application/json"}, + json={"access_token": "sample_access_token", "refresh_token": "sample_refresh_token"}, + additional_matcher=lambda req: req.json() == {'grant_type': 'refresh_token', 'refresh_token': 'sample_refresh_token'} + ) + mocker.start() + self.addCleanup(mocker.stop) + + token = self.session.refresh_token( + "https://www.wixapis.com/oauth/access", + refresh_token="sample_refresh_token" + ) + + self.assertEqual(token, {"access_token": "sample_access_token", "refresh_token": "sample_refresh_token"})