From 090dfde99137016a280645c3d83d5636466abac1 Mon Sep 17 00:00:00 2001 From: Brandon Wong Date: Fri, 6 Nov 2026 15:20:30 -0500 Subject: [PATCH] fix: send token request parameters in the request body Co-Authored-By: Claude Opus 5.5 --- duo_universal/client.py | 2 +- tests/test_exchange_authorization_code.py | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/duo_universal/client.py b/duo_universal/client.py index 5c9aefd..99e376b 100644 --- a/duo_universal/client.py +++ b/duo_universal/client.py @@ -362,7 +362,7 @@ def exchange_authorization_code_for_2fa_result(self, duoCode, username, nonce=No ca_bundle_version=CA_BUNDLE_VERSION, ca_pinning_status=ca_pinning_status) response = requests.post(token_endpoint, - params=all_args, + data=all_args, headers={"user-agent": user_agent}, verify=self._duo_certs, diff --git a/tests/test_exchange_authorization_code.py b/tests/test_exchange_authorization_code.py index 35501c3..d9b567e 100644 --- a/tests/test_exchange_authorization_code.py +++ b/tests/test_exchange_authorization_code.py @@ -143,6 +143,21 @@ def test_exchange_authorization_code_success(self, mock_jwt, mock_post): output = self.client.exchange_authorization_code_for_2fa_result(DUO_CODE, USERNAME) self.assertEqual(output, self.jwt_decode) + @patch('requests.post') + @patch('jwt.decode') + def test_exchange_authorization_code_sends_args_in_body(self, mock_jwt, mock_post): + """ + Test that the duo_code and client_assertion are sent in the + request body, not the URL query string + """ + mock_post.return_value.status_code = REQUESTS_POST_SUCCESS + mock_jwt.return_value = self.jwt_decode + self.client.exchange_authorization_code_for_2fa_result(DUO_CODE, USERNAME) + kwargs = mock_post.call_args.kwargs + self.assertNotIn('params', kwargs) + self.assertEqual(kwargs['data']['code'], DUO_CODE) + self.assertIn('client_assertion', kwargs['data']) + @patch('requests.post') def test_exchange_authorization_nonce(self, mock_post): """