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
Show file tree
Hide file tree
Changes from 1 commit
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
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
8 changes: 7 additions & 1 deletion requests_oauthlib/oauth2_session.py
Original file line number Diff line number Diff line change
Expand Up @@ -473,9 +473,15 @@ def refresh_token(
log.debug("Invoking refresh_token_request hook %s.", hook)
token_url, headers, body = hook(token_url, headers, body)

try:
body = dict(urldecode(body))
except ValueError:
log.debug("Could not decode body as urlencoded data. Using body in request as is: %s", body)
pass

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