googleapis/mcp-toolbox · error
google ID token verification failure: %w
Error message
google ID token verification failure: %w
What it means
GetClaimsFromHeader verifies the Google ID token from the <name>_token header using google.golang.org/api/idtoken.Validate with the configured ClientID as audience. Any verification error (bad signature, expired token, wrong issuer/audience, malformed JWT) is wrapped as 'google ID token verification failure'.
Source
Thrown at internal/auth/google/google.go:128
func (a AuthService) IsMCPEnabled() bool {
return a.McpEnabled
}
func (a AuthService) GetScopesRequired() []string {
return a.ScopesRequired
}
func (a AuthService) GetAuthorizationServer() string {
return "https://accounts.google.com"
}
// Verifies Google ID token and return claims
func (a AuthService) GetClaimsFromHeader(ctx context.Context, h http.Header) (map[string]any, error) {
if token := h.Get(a.Name + "_token"); token != "" {
payload, err := idtoken.Validate(ctx, token, a.ClientID)
if err != nil {
return nil, fmt.Errorf("google ID token verification failure: %w", err)
}
return payload.Claims, nil
}
return nil, nil
}
// ValidateMCPAuth handles MCP auth token validation for Google
func (a AuthService) ValidateMCPAuth(ctx context.Context, h http.Header) (map[string]any, error) {
tokenString := h.Get("Authorization")
if tokenString == "" {
return nil, &auth.MCPAuthError{Code: http.StatusUnauthorized, Message: "missing access token", ScopesRequired: a.ScopesRequired}
}
headerParts := strings.Split(tokenString, " ")
if len(headerParts) != 2 || strings.ToLower(headerParts[0]) != "bearer" {
return nil, &auth.MCPAuthError{Code: http.StatusUnauthorized, Message: "authorization header must be in the format 'Bearer <token>'", ScopesRequired: a.ScopesRequired}
}
View on GitHub (pinned to 8cc6e09de2)
Solutions
- Fetch a fresh ID token for the configured audience (e.g. gcloud auth print-identity-token or a Google auth library) and resend
- Ensure the clientId/audience configured in the google auth service matches the token's aud claim
- Verify you are sending an ID token, not an access token, in the <name>_token header
- Check machine clock sync (NTP) and outbound connectivity to token verification endpoints
- Inspect the wrapped inner error (%w) for the exact verification reason
Example fix
// before curl -H "my_service_token: ya29.access-token..." ... // after curl -H "my_service_token: $(gcloud auth print-identity-token --audiences=https://my-app.apps.googleusercontent.com)" ...
Defensive patterns
Strategy: try-catch
Validate before calling
// client-side: ensure an ID token is fresh and audience-correct before sending
tok, err := idtoken.NewTokenSource(ctx, audience).Token() // or gcloud print-identity-token
if err != nil || tok == nil {
return errors.New("no valid ID token available")
} Try / catch
claims, err := svc.GetClaimsFromHeader(ctx, header)
if err != nil {
var ue *idtoken.Error // or inspect wrapped cause
if strings.Contains(err.Error(), "ID token verification failure") {
// refresh token and retry once
header.Set(name+"_token", freshIDToken())
claims, err = svc.GetClaimsFromHeader(ctx, header)
}
} Prevention
- Refresh ID tokens before expiry; ID tokens typically last ~1 hour
- Send an ID token, never an access token, in the <name>_token header
- Keep client clock synchronized (NTP)
- Ensure the configured clientId/audience matches the token's aud
- Allow egress to Google's token/cert endpoints
When it happens
Trigger: Sending an expired, malformed, tampered, or wrongly signed ID token in the <serviceName>_token header; token issued for a different client than the configured ClientID; no network access to Google's cert endpoints (offline environments).
Common situations: Clock skew on client machine causing 'token used too early'/'expired'; swapping access token for ID token in the header; forgetting to configure clientId/audience so validation target mismatches; firewall blocking fetch of Google public keys.
Related errors
- failed to parse and verify JWT token: %w
- invalid JWT token
- `audience` or `clientId` is required when `mcpEnabled` is tr
- `audience` is not allowed when `mcpEnabled` is false
- `scopesRequired` is not allowed when `mcpEnabled` is false
AI-assisted analysis of googleapis/mcp-toolbox@8cc6e09de2 (2026-09-05).
Data as JSON: /api/errors/99959700839f23a8.
Report an issue: GitHub.