diff --git a/packages/google-auth/google/auth/transport/grpc.py b/packages/google-auth/google/auth/transport/grpc.py index 7482038589a3..e32827a691f3 100644 --- a/packages/google-auth/google/auth/transport/grpc.py +++ b/packages/google-auth/google/auth/transport/grpc.py @@ -274,6 +274,25 @@ def my_client_cert_callback(): ssl_credentials, google_auth_credentials ) + # Set default max_metadata_size to 32768 (32 KB) to prevent gRPC C-core metadata + # limit rejections (default 8 KB) when Post-Quantum Cryptography (PQC) bearer tokens + # (ML-DSA-65 is 4.5 KB) or large trace headers are used. + options = kwargs.pop("options", None) + if options is None: + kwargs["options"] = [("grpc.max_metadata_size", 32768)] + elif isinstance(options, (list, tuple)): + opts = list(options) + if not any( + isinstance(opt, (list, tuple)) + and len(opt) >= 2 + and opt[0] == "grpc.max_metadata_size" + for opt in opts + ): + opts.append(("grpc.max_metadata_size", 32768)) + kwargs["options"] = opts + else: + kwargs["options"] = options + return grpc.secure_channel(target, composite_credentials, **kwargs) diff --git a/packages/google-auth/tests/transport/test_grpc.py b/packages/google-auth/tests/transport/test_grpc.py index 9f3c117ed933..10bb08bcf1af 100644 --- a/packages/google-auth/tests/transport/test_grpc.py +++ b/packages/google-auth/tests/transport/test_grpc.py @@ -275,6 +275,28 @@ def test_secure_authorized_channel_explicit_ssl( ssl_credentials, metadata_call_credentials.return_value ) + def test_secure_authorized_channel_pqc_max_metadata_size( + self, + secure_channel, + ssl_channel_credentials, + metadata_call_credentials, + composite_channel_credentials, + get_client_ssl_credentials, + ): + credentials = mock.Mock() + request = mock.Mock() + target = "example.com:80" + ssl_credentials = mock.Mock() + + # Call without explicit options; should automatically add grpc.max_metadata_size=32768 + google.auth.transport.grpc.secure_authorized_channel( + credentials, request, target, ssl_credentials=ssl_credentials + ) + + _, kwargs = secure_channel.call_args + assert "options" in kwargs + assert ("grpc.max_metadata_size", 32768) in kwargs["options"] + def test_secure_authorized_channel_mutual_exclusive( self, secure_channel,