Skip to content

Commit 0495149

Browse files
authored
Ability to parse JWT UserInfo payload (#549)
* fix: allow JWT payload for userinfo response See: https://openid.net/specs/openid-connect-core-1_0-final.html#UserInfoResponse * fix: added test for JWT userinfo payload * fix: content-type case thx @qbey
1 parent 2ffeb3a commit 0495149

File tree

2 files changed

+31
-0
lines changed

2 files changed

+31
-0
lines changed

mozilla_django_oidc/auth.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,12 @@ def get_userinfo(self, access_token, id_token, payload):
261261
proxies=self.get_settings("OIDC_PROXY", None),
262262
)
263263
user_response.raise_for_status()
264+
265+
if user_response.headers.get("content-type", "").lower().startswith("application/jwt"):
266+
# OIDC userinfo claims can be encoded as JWT
267+
return self.verify_token(user_response.text)
268+
269+
# otherwise process as JSON payload
264270
return user_response.json()
265271

266272
def authenticate(self, request, **kwargs):

tests/test_auth.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -831,6 +831,31 @@ def update_user(user, claims):
831831

832832
self.assertEqual(User.objects.get().first_name, "a_username")
833833

834+
@patch("mozilla_django_oidc.auth.requests")
835+
@patch("mozilla_django_oidc.auth.OIDCAuthenticationBackend.verify_token")
836+
def test_get_userinfo_with_jwt_response(self, verify_token_mock, request_mock):
837+
"""Test get_userinfo with a JWT response."""
838+
auth_request = RequestFactory().get("/foo", {"code": "foo", "state": "bar"})
839+
auth_request.session = {}
840+
841+
# Mock the response from the userinfo endpoint
842+
jwt_response = Mock()
843+
jwt_response.headers = {"content-type": "application/jwt"}
844+
jwt_response.text = "mocked_jwt_token"
845+
request_mock.get.return_value = jwt_response
846+
847+
# Mock the verify_token method to return a specific payload
848+
verify_token_mock.return_value = {"email": "email@example.com", "name": "John Doe"}
849+
850+
# Call the get_userinfo method
851+
user_info = self.backend.get_userinfo("access_token", "id_token", {})
852+
853+
# Assert that verify_token was called with the correct token
854+
verify_token_mock.assert_called_once_with("mocked_jwt_token")
855+
856+
# Assert that the returned user info matches the expected payload
857+
self.assertEqual(user_info, {"email": "email@example.com", "name": "John Doe"})
858+
834859

835860
class OIDCAuthenticationBackendRS256WithKeyTestCase(TestCase):
836861
"""Authentication tests with ALG RS256 and provided IdP Sign Key."""

0 commit comments

Comments
 (0)