diff --git a/google/auth/impersonated_credentials.py b/google/auth/impersonated_credentials.py index e2724382a..8ac0a420e 100644 --- a/google/auth/impersonated_credentials.py +++ b/google/auth/impersonated_credentials.py @@ -640,7 +640,14 @@ def refresh(self, request): "Error getting ID token: {}".format(response.json()) ) - id_token = response.json()["token"] + try: + id_token = response.json()["token"] + except (KeyError, ValueError) as caught_exc: + new_exc = exceptions.RefreshError( + "No ID token in response.", response.json() + ) + raise new_exc from caught_exc + self.token = id_token self.expiry = datetime.utcfromtimestamp( jwt.decode(id_token, verify=False)["exp"] diff --git a/tests/test_impersonated_credentials.py b/tests/test_impersonated_credentials.py index ab92e0bd9..b4566576e 100644 --- a/tests/test_impersonated_credentials.py +++ b/tests/test_impersonated_credentials.py @@ -761,6 +761,28 @@ def test_refresh_failure(self): assert excinfo.match("Error getting ID token") + def test_refresh_failure_missing_token_in_200_response(self): + credentials = self.make_credentials(lifetime=None) + credentials.expiry = None + credentials.token = "token" + id_creds = impersonated_credentials.IDTokenCredentials( + credentials, target_audience="audience" + ) + + # Response has 200 OK status but is missing the "token" field + response = mock.create_autospec(transport.Response, instance=False) + response.status_code = http_client.OK + response.json = mock.Mock(return_value={"not_token": "something"}) + + with mock.patch( + "google.auth.transport.requests.AuthorizedSession.post", + return_value=response, + ): + with pytest.raises(exceptions.RefreshError) as excinfo: + id_creds.refresh(None) + + assert excinfo.match("No ID token in response") + def test_refresh_failure_http_error(self, mock_donor_credentials): credentials = self.make_credentials(lifetime=None)