Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support non-x-www-form-urlencoded bodies returned from refresh_token_request compliance hook #545

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions requests_oauthlib/compliance_fixes/__init__.py
Original file line number Diff line number Diff line change
@@ -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
36 changes: 36 additions & 0 deletions requests_oauthlib/compliance_fixes/wix.py
Original file line number Diff line number Diff line change
@@ -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
5 changes: 4 additions & 1 deletion requests_oauthlib/oauth2_session.py
Original file line number Diff line number Diff line change
@@ -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,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To check the content type instead of catching the ValueError, this could just become:

data=body if headers["Content-Type"] == "application/json" else dict(urldecode(body)),

auth=auth,
timeout=timeout,
headers=headers,
44 changes: 44 additions & 0 deletions tests/test_compliance_fixes.py
Original file line number Diff line number Diff line change
@@ -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"})