diff --git a/google/auth/external_account.py b/google/auth/external_account.py index 001b26f7f..c45e6f213 100644 --- a/google/auth/external_account.py +++ b/google/auth/external_account.py @@ -385,7 +385,14 @@ def refresh(self, request): additional_headers=additional_headers, ) self.token = response_data.get("access_token") - lifetime = datetime.timedelta(seconds=response_data.get("expires_in")) + expires_in = response_data.get("expires_in") + # Some services do not respect the OAUTH2.0 RFC and send expires_in as a + # JSON String. + if isinstance(expires_in, str): + expires_in = int(expires_in) + + lifetime = datetime.timedelta(seconds=expires_in) + self.expiry = now + lifetime @_helpers.copy_docstring(credentials.CredentialsWithQuotaProject) diff --git a/system_tests/secrets.tar.enc b/system_tests/secrets.tar.enc index c1792fbd9..fd667ebc8 100644 Binary files a/system_tests/secrets.tar.enc and b/system_tests/secrets.tar.enc differ diff --git a/tests/test_external_account.py b/tests/test_external_account.py index fd511aa44..9e9d1f58a 100644 --- a/tests/test_external_account.py +++ b/tests/test_external_account.py @@ -625,19 +625,20 @@ def test_is_workforce_pool_with_users_and_impersonation(self, audience): # Even though impersonation is used, is_workforce_pool should still return True. assert credentials.is_workforce_pool is True + @pytest.mark.parametrize("mock_expires_in", [2800, "2800"]) @mock.patch( "google.auth.metrics.python_and_auth_lib_version", return_value=LANG_LIBRARY_METRICS_HEADER_VALUE, ) @mock.patch("google.auth._helpers.utcnow", return_value=datetime.datetime.min) def test_refresh_without_client_auth_success( - self, unused_utcnow, mock_auth_lib_value + self, unused_utcnow, mock_auth_lib_value, mock_expires_in ): response = self.SUCCESS_RESPONSE.copy() # Test custom expiration to confirm expiry is set correctly. - response["expires_in"] = 2800 + response["expires_in"] = mock_expires_in expected_expiry = datetime.datetime.min + datetime.timedelta( - seconds=response["expires_in"] + seconds=int(mock_expires_in) ) headers = { "Content-Type": "application/x-www-form-urlencoded",