{"record":{"id":"d11605b3d682d8e9","repo":"googleapis/mcp-toolbox","slug":"error-creating-service-from-oauth-access-token-w","errorCode":null,"errorMessage":"error creating service from OAuth access token: %w","messagePattern":"error creating service from OAuth access token: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/sources/cloudhealthcare/cloud_healthcare.go","lineNumber":298,"sourceCode":"\t}\n\tif resp.StatusCode > 299 {\n\t\treturn nil, fmt.Errorf(\"status %d %s: %s\", resp.StatusCode, resp.Status, respBytes)\n\t}\n\tvar jsonMap map[string]interface{}\n\tif err := json.Unmarshal(respBytes, &jsonMap); err != nil {\n\t\treturn nil, fmt.Errorf(\"could not unmarshal response as json: %w\", err)\n\t}\n\treturn jsonMap, nil\n}\n\nfunc (s *Source) getService(tokenStr string) (*healthcare.Service, error) {\n\tsvc := s.Service()\n\tvar err error\n\t// Initialize new service if using user OAuth token\n\tif s.UseClientAuthorization() {\n\t\tsvc, err = s.ServiceCreator()(tokenStr)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error creating service from OAuth access token: %w\", err)\n\t\t}\n\t}\n\treturn svc, nil\n}\n\nfunc isAlphanumeric(c byte) bool {\n\treturn (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9')\n}\n\nfunc isValidAPIVersion(v string) bool {\n\tif len(v) < 2 || v[0] != 'v' {\n\t\treturn false\n\t}\n\t// The character after 'v' must be a digit '1'-'9'\n\tif v[1] < '1' || v[1] > '9' {\n\t\treturn false\n\t}\n\tfor i := 2; i < len(v); i++ {","sourceCodeStart":280,"sourceCodeEnd":316,"githubUrl":"https://github.com/googleapis/mcp-toolbox/blob/8cc6e09de2ad7b8bffc77751799585a1401a48eb/internal/sources/cloudhealthcare/cloud_healthcare.go#L280-L316","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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"],"exampleFix":"// before: sending stale token\nhttpClient.Header.Set(\"Authorization\", \"Bearer \" + staleToken)\n// after\nif token.Expiry.Before(time.Now().Add(5*time.Minute)) {\n    token, err = tokenSource.Token()\n    if err != nil { return err }\n}\nhttpClient.Header.Set(\"Authorization\", \"Bearer \" + token.AccessToken)","handlingStrategy":"validation","validationCode":"function validateOAuthToken(tok) {\n  if (!tok || tok.split('.').length < 2) return 'token malformed';\n  try {\n    const payload = JSON.parse(atob(tok.split('.')[1].replace(/-/g, '+').replace(/_/g, '/')));\n    if (payload.exp * 1000 < Date.now() + 60000) return 'token expired';\n    if (!(payload.scope || '').includes('cloud-platform')) return 'missing cloud-platform scope';\n    return null;\n  } catch { return 'token not a JWT'; }\n}","typeGuard":"function hasValidBearerAuth(headers) { const a = headers['authorization']; return typeof a === 'string' && /^Bearer [A-Za-z0-9\\-._~+/]+=*$/.test(a); }","tryCatchPattern":"try {\n  const res = await tool.invoke(params, { authToken: accessToken });\n} catch (e) {\n  if (/error creating service from OAuth access token/.test(e.message)) {\n    accessToken = await refreshAccessToken(); // token expired or malformed\n    return tool.invoke(params, { authToken: accessToken });\n  }\n  throw e;\n}","preventionTips":["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"],"tags":["oauth","authentication","google-cloud","token"],"backgroundTag":"oauth-token-invalid","analyzedSha":"8cc6e09de2ad7b8bffc77751799585a1401a48eb","analyzedAt":"2026-09-05T01:10:36.887Z","contentChangedAt":"2026-09-05T01:10:36.887Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}