Skip to content

Scope Vertex AI credentials to cloud-platform#6596

Open
subhashpolisetti wants to merge 1 commit into
spring-projects:mainfrom
subhashpolisetti:google-genai-scope-vertex-credentials
Open

Scope Vertex AI credentials to cloud-platform#6596
subhashpolisetti wants to merge 1 commit into
spring-projects:mainfrom
subhashpolisetti:google-genai-scope-vertex-credentials

Conversation

@subhashpolisetti

@subhashpolisetti subhashpolisetti commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Problem

In Vertex AI mode, the google-genai starter loads the service-account
credentials from spring.ai.google.genai.credentials-uri and currently
applies them to the client without an OAuth scope. GoogleCredentials.fromStream
returns scopeless credentials, so Vertex AI rejects the access-token
refresh with invalid_scope and no chat request can complete:

GoogleAuthException: Error getting access token for service account:
400 Bad Request POST https://oauth2.googleapis.com/token
{"error":"invalid_scope"}

Only the explicit credentials-uri path is affected; the Application
Default Credentials path is scoped by the underlying SDK. There is no
configuration workaround today: there is no scope property, and the
Client bean is @ConditionalOnMissingBean with no customizer, so the
only escape is replacing the entire bean.

Fix

Scope the credentials loaded from credentials-uri to cloud-platform,
matching the scope the SDK applies to Application Default Credentials.

Testing

Adds GoogleGenAiChatAutoConfigurationTests, which is fully
self-contained (no network, no real key, no environment variables — it
generates a throwaway RSA keypair and a synthetic service-account JSON):

  • one test pins the root cause: credentials from
    GoogleCredentials.fromStream carry no scope;
  • one test verifies the fix: the loaded credentials are scoped to
    cloud-platform.

I also verified the behavior end to end against a real Google Cloud
service-account key. The unit test can only assert the scope offline,
because invalid_scope is returned by a live token exchange — the exact
call the SDK makes (refreshIfExpired() on the provided credentials):

// unscoped credentials (current behavior)
GoogleCredentials.fromStream(key).refreshIfExpired();
// 400 Bad Request POST https://oauth2.googleapis.com/token
// {"error":"invalid_scope","error_description":"Invalid OAuth scope or ID token audience provided."}

// scoped to cloud-platform (the fix)
GoogleCredentials.fromStream(key)
    .createScoped(List.of("https://www.googleapis.com/auth/cloud-platform"))
    .refreshIfExpired();
// access token obtained

Fixes #6595

In Vertex AI mode, `GoogleGenAiChatAutoConfiguration` loaded the service
account credentials from `credentials-uri` via
`GoogleCredentials.fromStream` and applied them without an OAuth scope.
Such credentials are scopeless, so Vertex AI rejects the access-token
refresh with `invalid_scope` and no chat request can complete. This
affects only the explicit `credentials-uri` path; the Application
Default Credentials path is scoped by the underlying SDK.

Scope the loaded credentials to `cloud-platform`, matching the scope the
SDK applies to Application Default Credentials, so that service account
keys supplied through `credentials-uri` authenticate successfully.

Fixes spring-projects#6595

Signed-off-by: subhash polisetti <subhashr161347@gmail.com>

@mikecollard mikecollard left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

lgtm

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

GoogleGenAiChatAutoConfiguration builds Vertex AI credentials unscoped → invalid_scope on token refresh

3 participants