googleapis/mcp-toolbox · error
error creating service from OAuth access token: %w
Error message
error creating service from OAuth access token: %w
What it means
getService builds a Cloud Healthcare service client on the fly when the request carries a client-supplied OAuth access token (UseClientAuthorization()). It calls the configured ServiceCreator with the token string; if that constructor (which uses google oauth token sources / option.WithTokenSource) fails, the error is wrapped with this message. It indicates the OAuth token could not be turned into an authenticated healthcare service client.
Source
Thrown at internal/sources/cloudhealthcare/cloud_healthcare.go:298
}
if resp.StatusCode > 299 {
return nil, fmt.Errorf("status %d %s: %s", resp.StatusCode, resp.Status, respBytes)
}
var jsonMap map[string]interface{}
if err := json.Unmarshal(respBytes, &jsonMap); err != nil {
return nil, fmt.Errorf("could not unmarshal response as json: %w", err)
}
return jsonMap, nil
}
func (s *Source) getService(tokenStr string) (*healthcare.Service, error) {
svc := s.Service()
var err error
// Initialize new service if using user OAuth token
if s.UseClientAuthorization() {
svc, err = s.ServiceCreator()(tokenStr)
if err != nil {
return nil, fmt.Errorf("error creating service from OAuth access token: %w", err)
}
}
return svc, nil
}
func isAlphanumeric(c byte) bool {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9')
}
func isValidAPIVersion(v string) bool {
if len(v) < 2 || v[0] != 'v' {
return false
}
// The character after 'v' must be a digit '1'-'9'
if v[1] < '1' || v[1] > '9' {
return false
}
for i := 2; i < len(v); i++ {View on GitHub (pinned to 8cc6e09de2)
Solutions
- Verify the client is sending a valid, non-expired OAuth 2.0 access token in the Authorization header
- Refresh the token before the call (expired access tokens last ~1 hour)
- Ensure the token has the https://www.googleapis.com/auth/cloud-platform scope
- Check the source's configured service endpoint / universe domain is reachable
- If using ADC-based auth instead, drop the client Authorization header so the default token source is used
Example fix
// before: sending stale token
httpClient.Header.Set("Authorization", "Bearer " + staleToken)
// after
if token.Expiry.Before(time.Now().Add(5*time.Minute)) {
token, err = tokenSource.Token()
if err != nil { return err }
}
httpClient.Header.Set("Authorization", "Bearer " + token.AccessToken) Defensive patterns
Strategy: validation
Validate before calling
function validateOAuthToken(tok) {
if (!tok || tok.split('.').length < 2) return 'token malformed';
try {
const payload = JSON.parse(atob(tok.split('.')[1].replace(/-/g, '+').replace(/_/g, '/')));
if (payload.exp * 1000 < Date.now() + 60000) return 'token expired';
if (!(payload.scope || '').includes('cloud-platform')) return 'missing cloud-platform scope';
return null;
} catch { return 'token not a JWT'; }
} Type guard
function hasValidBearerAuth(headers) { const a = headers['authorization']; return typeof a === 'string' && /^Bearer [A-Za-z0-9\-._~+/]+=*$/.test(a); } Try / catch
try {
const res = await tool.invoke(params, { authToken: accessToken });
} catch (e) {
if (/error creating service from OAuth access token/.test(e.message)) {
accessToken = await refreshAccessToken(); // token expired or malformed
return tool.invoke(params, { authToken: accessToken });
}
throw e;
} Prevention
- Refresh access tokens before expiry (~1 hour lifetime); refresh 5 minutes early
- Always request the https://www.googleapis.com/auth/cloud-platform scope
- Prefer ADC (omit the client Authorization header) when running on GCP infrastructure
- Check token is a well-formed JWT before sending
When it happens
Trigger: A user OAuth token passed via the client's Authorization header is malformed, expired, or cannot be parsed by the oauth2/google machinery inside s.ServiceCreator()(tokenStr); or the ServiceCreator itself is misconfigured (wrong endpoint/universe domain).
Common situations: MCP client sends an expired or truncated access token in the Authorization header; token lacks required scopes (cloud-platform); a custom service URL with an unreachable private endpoint was configured; clock skew invalidating the token.
Related errors
- retrieved token is invalid or expired
- error parsing access token: %w
- error creating client from OAuth access token: %w
- failed to create DataChatClient: %w
- failed to find default credentials: %w
AI-assisted analysis of googleapis/mcp-toolbox@8cc6e09de2 (2026-09-05).
Data as JSON: /api/errors/d11605b3d682d8e9.
Report an issue: GitHub.