diff --git a/src/google/adk/auth/auth_handler.py b/src/google/adk/auth/auth_handler.py index 15afb917..1a00d41b 100644 --- a/src/google/adk/auth/auth_handler.py +++ b/src/google/adk/auth/auth_handler.py @@ -215,6 +215,8 @@ class AuthHandler: } if auth_credential.oauth2.audience: params["audience"] = auth_credential.oauth2.audience + if auth_credential.oauth2.nonce: + params["nonce"] = auth_credential.oauth2.nonce # If using PKCE with S256, ensure a code_verifier exists. # If not provided in the credential, generate a cryptographically secure diff --git a/tests/unittests/auth/test_auth_handler.py b/tests/unittests/auth/test_auth_handler.py index c2ef3912..f63c6170 100644 --- a/tests/unittests/auth/test_auth_handler.py +++ b/tests/unittests/auth/test_auth_handler.py @@ -355,6 +355,59 @@ class TestGenerateAuthUri: assert "code_verifier" in kwargs assert kwargs["code_verifier"] == result.oauth2.code_verifier + @patch("google.adk.auth.auth_handler.OAuth2Session") + def test_generate_auth_uri_with_nonce( + self, mock_oauth2_session, oauth2_auth_scheme, oauth2_credentials + ): + """Test that a nonce is forwarded to the authorization request.""" + oauth2_credentials.oauth2.nonce = "test_nonce" + exchanged = oauth2_credentials.model_copy(deep=True) + + config = AuthConfig( + auth_scheme=oauth2_auth_scheme, + raw_auth_credential=oauth2_credentials, + exchanged_auth_credential=exchanged, + ) + + mock_client = Mock() + mock_oauth2_session.return_value = mock_client + mock_client.create_authorization_url.return_value = ( + "https://example.com/oauth2/authorize?nonce=test_nonce", + "mock_state", + ) + + handler = AuthHandler(config) + handler.generate_auth_uri() + + _, kwargs = mock_client.create_authorization_url.call_args + assert kwargs["nonce"] == "test_nonce" + + @patch("google.adk.auth.auth_handler.OAuth2Session") + def test_generate_auth_uri_without_nonce( + self, mock_oauth2_session, oauth2_auth_scheme, oauth2_credentials + ): + """Test that no nonce is sent when the credential has none.""" + exchanged = oauth2_credentials.model_copy(deep=True) + + config = AuthConfig( + auth_scheme=oauth2_auth_scheme, + raw_auth_credential=oauth2_credentials, + exchanged_auth_credential=exchanged, + ) + + mock_client = Mock() + mock_oauth2_session.return_value = mock_client + mock_client.create_authorization_url.return_value = ( + "https://example.com/oauth2/authorize", + "mock_state", + ) + + handler = AuthHandler(config) + handler.generate_auth_uri() + + _, kwargs = mock_client.create_authorization_url.call_args + assert "nonce" not in kwargs + def test_generate_auth_uri_unsupported_pkce_method( self, oauth2_auth_scheme, oauth2_credentials ):