spring-projects / spring-projects/spring-ai
GoogleGenAiChatAutoConfiguration builds Vertex AI credentials unscoped → invalid_scope on token refresh
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 9.5k
- Forks
- 2.9k
- Avg merge
- 1d 7h
- Merged PRs (30d)
- 6
Description
Bug description
In Vertex AI mode, the google-genai starter applies the service-account credentials loaded from spring.ai.google.genai.credentials-uri without an OAuth scope, so the access-token refresh is rejected by Google with invalid_scope.
GoogleGenAiChatAutoConfiguration#configureVertexAi(...) builds credentials via GoogleCredentials.fromStream(is) and passes them straight to the client builder:
private void configureVertexAi(Client.Builder builder, GoogleGenAiConnectionProperties props) throws IOException {
...
builder.project(props.getProjectId()).location(props.getLocation()).vertexAI(true);
if (props.getCredentialsUri() != null) {
try (var is = props.getCredentialsUri().getInputStream()) {
builder.credentials(GoogleCredentials.fromStream(is)); // <-- not scoped
}
}
}
GoogleCredentials.fromStream(...) on a service-account key returns a scopeless ServiceAccountCredentials. Vertex AI requires the https://www.googleapis.com/auth/cloud-platform scope, so token refresh fails:
com.google.auth.oauth2.GoogleAuthException: Error getting access token for service account: 400 Bad Request
POST https://oauth2.googleapis.com/token
{"error":"invalid_scope","error_description":"Invalid OAuth scope or ID token audience provided."}
iss: <service-account>@<project>.iam.gserviceaccount.com
This only affects the explicit credentials-uri path (the ADC path is scoped elsewhere), and there is currently no way to fix it via configuration: GoogleGenAiConnectionProperties exposes no scope property, and the googleGenAiClient bean offers no Client.Builder customizer hook (it is only @ConditionalOnMissingBean), so the sole workaround is to replace the entire Client bean.
Related: #5242 (credentials-uri not applied to the client in 1.1.2). In 2.0.0 the credentials are applied — but unscoped — so this is the follow-on defect.
Environment
- Spring AI: 2.0.0 (
spring-ai-starter-model-google-genai/spring-ai-autoconfigure-model-google-genai:2.0.0) - google-genai SDK:
com.google.genai:google-genai:1.58.0 - Spring Boot: 4.1.x
- Java: 21
- Mode: Vertex AI (
spring.ai.google.genai.vertex-ai=true), credentials viaspring.ai.google.genai.credentials-uri - No vector store involved
Steps to reproduce
- Configure Vertex AI mode with an explicit service-account key (not ADC):
spring.ai.google.genai.vertex-ai=true spring.ai.google.genai.project-id=<project> spring.ai.google.genai.location=us-central1 spring.ai.google.genai.credentials-uri=file:/path/to/service-account.json spring.ai.model.chat=google-genai - Autowire
ChatModel(orChatClient.Builder) and make any call, e.g.chatClient.prompt("hi").call().content(). - The call fails:
GoogleAuthException: Error getting access token for service account: 400 Bad Request/{"error":"invalid_scope"}.
Expected behavior
Service-account credentials supplied via spring.ai.google.genai.credentials-uri should authenticate Vertex AI calls successfully. The autoconfiguration should scope them to cloud-platform (as the legacy vertex-ai-gemini starter did), e.g.:
builder.credentials(GoogleCredentials.fromStream(is)
.createScoped(java.util.List.of("https://www.googleapis.com/auth/cloud-platform")));
Ideally also expose a way to configure this without replacing the client — a scope property and/or an ObjectProvider<Consumer<Client.Builder>> customizer hook on the googleGenAiClient bean.
Minimal Complete Reproducible example
Workaround that confirms the root cause — supplying a scoped Client (the starter's bean is @ConditionalOnMissingBean, so it backs off) makes the same call succeed:
@TestConfiguration
class ScopedGoogleGenAiClientConfig {
@Bean
Client googleGenAiClient(Environment env) throws IOException {
var credentials = GoogleCredentials
.fromStream(new FileInputStream(env.getProperty("spring.ai.google.genai.credentials-uri-path")))
.createScoped(List.of("https://www.googleapis.com/auth/cloud-platform")); // <-- the missing step
return Client.builder()
.project(env.getProperty("spring.ai.google.genai.project-id"))
.location(env.getProperty("spring.ai.google.genai.location"))
.vertexAI(true)
.credentials(credentials)
.build();
}
}
With the stock autoconfiguration (no custom Client), the same setup throws invalid_scope; adding .createScoped(cloud-platform) is the only difference that makes it pass.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start at GoogleGenAiChatAutoConfiguration#configureVertexAi(...) and trace the credentials-uri branch from GoogleCredentials.fromStream(is) into the Client.Builder. Verify the Vertex AI service-account credentials use the cloud-platform scope, then add or update coverage for the explicit credentials-uri path and confirm the invalid_scope scenario is resolved without changing the ADC path.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- ai, authentication, backend
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 76/100