Skip to content

fix(auth): pass quotaProjectId to ImpersonatedCredentials and clear it from sourceCredentials - #14450

Draft
lsirac wants to merge 1 commit into
mainfrom
fix/b-563846713-impersonated-quota-project
Draft

lsirac wants to merge 1 commit into
mainfrom
fix/b-563846713-impersonated-quota-project

Conversation

@lsirac

@lsirac lsirac commented Sep 20, 2026

Copy link
Copy Markdown
Contributor

Summary

When ExternalAccountCredentials.buildImpersonatedCredentials() creates an ImpersonatedCredentials instance, it previously left quotaProjectId on sourceCredentials and omitted it on ImpersonatedCredentials. As a result, ImpersonatedCredentials.refreshAccessToken() sent x-goog-user-project on the iamcredentials.googleapis.com generateAccessToken request using the federated identity, which fails with 403 USER_PROJECT_DENIED when only the impersonated service account has serviceusage.services.use permission on the quota project. Meanwhile, ImpersonatedCredentials.getQuotaProjectId() returned null.

This change clears quotaProjectId on sourceCredentials across AwsCredentials, PluggableAuthCredentials, and IdentityPoolCredentials, and passes this.quotaProjectId to ImpersonatedCredentials.newBuilder().

Bug: b/563846713

Testing

  • Unit tests: mvn test -pl oauth2_http -Dtest=ExternalAccountCredentialsTest,PluggableAuthCredentialsTest,ImpersonatedCredentialsTest
  • Live GCP verification against STS, IAMCredentials, and Pub/Sub in cicpclientproj: https://paste.googleplex.com/6012380862087168

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates ExternalAccountCredentials to propagate the quotaProjectId to impersonated credentials while clearing it from the source credentials. It also adds a test to verify this behavior. The review feedback correctly identifies a compilation error in the new test method, which needs to declare throws IOException because ExternalAccountCredentials.fromJson throws a checked exception.

}

@Test
void buildImpersonatedCredentials_withQuotaProjectId() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The method ExternalAccountCredentials.fromJson throws a checked IOException. Since this exception is not caught within the test method, the method signature must declare throws IOException to avoid a compilation error.

Suggested change
void buildImpersonatedCredentials_withQuotaProjectId() {
void buildImpersonatedCredentials_withQuotaProjectId() throws IOException {

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant