{"record":{"id":"e163b61211899c6c","repo":"can1357/oh-my-pi","slug":"refusing-to-send-official-xai-oauth-credentials-to","errorCode":null,"errorMessage":"Refusing to send official xAI OAuth credentials to custom endpoint ${transport.baseURL}. Configure an API key for provider \"xai-oauth\".","messagePattern":"Refusing to send official xAI OAuth credentials to custom endpoint (.+?)\\. Configure an API key for provider \"xai-oauth\"\\.","errorType":"exception","errorClass":"SearchProviderError","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/web/search/providers/xai.ts","lineNumber":410,"sourceCode":"\t\treturn xaiResolver(ctx);\n\t};\n\treturn { provider: \"xai-oauth\", keyOrResolver };\n}\n\n/** Execute xAI Responses API web search. */\nexport async function searchXAI(params: SearchParams): Promise<SearchResponse> {\n\tconst auth = resolveXAIWebSearchAuth(params);\n\tconst transport = params.modelRegistry\n\t\t? resolveXAIHttpTransport(params.modelRegistry, auth.provider, XAI_WEB_SEARCH_MODEL)\n\t\t: { baseURL: XAI_DEFAULT_BASE_URL };\n\tconst customEndpoint = transport.baseURL.replace(/\\/+$/, \"\") !== XAI_DEFAULT_BASE_URL;\n\tconst credentialOrigin = params.authStorage.getCredentialOrigin(auth.provider);\n\tif (\n\t\tcustomEndpoint &&\n\t\tauth.provider === \"xai-oauth\" &&\n\t\t(credentialOrigin?.kind === \"oauth\" || credentialOrigin?.kind === \"env\")\n\t) {\n\t\tthrow new SearchProviderError(\n\t\t\t\"xai\",\n\t\t\t`Refusing to send official xAI OAuth credentials to custom endpoint ${transport.baseURL}. Configure an API key for provider \"xai-oauth\".`,\n\t\t);\n\t}\n\tconst keyOrResolver: ApiKey = customEndpoint\n\t\t? params.authStorage.resolver(auth.provider, { sessionId: params.sessionId })\n\t\t: auth.keyOrResolver;\n\n\tconst resultCap = clampNumResults(params.numSearchResults ?? params.limit, DEFAULT_NUM_RESULTS, MAX_NUM_RESULTS);\n\tconst response = await withAuth(keyOrResolver, (key: string) => callXAIResponses(key, params, transport), {\n\t\tsignal: params.signal,\n\t\tmissingKeyMessage: 'xAI credentials not found. Set XAI_API_KEY or configure an API key for provider \"xai\".',\n\t});\n\tconst parsed = parseResponse(response, resultCap);\n\tif (!parsed.answer && parsed.sources.length === 0) {\n\t\tthrow new SearchProviderError(\"xai\", \"xAI web_search returned no answer or sources\", 502);\n\t}\n\treturn parsed;","sourceCodeStart":392,"sourceCodeEnd":428,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/web/search/providers/xai.ts#L392-L428","documentation":"searchXAI refuses to send official xAI OAuth credentials (from OAuth login or environment) to a non-default/custom endpoint. Because OAuth tokens grant broad account access, silently forwarding them to an arbitrary baseURL would be a credential-leak risk. The library throws this SearchProviderError and demands an explicit API key for provider \"xai-oauth\" instead.","triggerScenarios":"All of: (1) transport.baseURL differs from XAI_DEFAULT_BASE_URL (custom endpoint configured via modelRegistry/transport), (2) selected auth provider is \"xai-oauth\", and (3) credentialOrigin.kind is \"oauth\" or \"env\" (i.e. the credential came from OAuth login or XAI_OAUTH_TOKEN, not an explicitly stored API key).","commonSituations":"User logged in via `omp` xAI OAuth but also configured a custom/compat endpoint (e.g. an OpenAI-compatible proxy) in the model registry; CI sets XAI_OAUTH_TOKEN while a gateway baseURL is configured; switched the provider endpoint to a regional mirror without swapping to an API key.","solutions":["Configure a plain API key for provider \"xai-oauth\" (or provider \"xai\") so the OAuth credential is not used against the custom endpoint","Remove the custom baseURL override so requests go to the official xAI endpoint, where OAuth is allowed","Unset XAI_OAUTH_TOKEN and log out of xAI OAuth if you intend to use only an API key with the custom endpoint","Store the API key explicitly in auth storage for the xai provider so resolveXAIWebSearchAuth picks provider \"xai\" instead of \"xai-oauth\""],"exampleFix":"// before: OAuth creds + custom endpoint -> throws\n// (XAI_OAUTH_TOKEN set, baseURL = https://my-proxy.example.com/v1)\n// after: use an API key for the custom endpoint\nprocess.env.XAI_OAUTH_TOKEN = \"\"; // remove OAuth token\nprocess.env.XAI_API_KEY = \"xai-xxxxxxxx\"; // or store via auth storage for provider \"xai\"","handlingStrategy":"validation","validationCode":"const usingOAuth = Boolean(process.env.XAI_OAUTH_TOKEN) || authOrigin?.kind === \"oauth\";\nconst customEndpoint = baseURL !== officialXAIBaseURL;\nif (usingOAuth && customEndpoint) {\n  // fix config before calling:\n  // unset XAI_OAUTH_TOKEN and set XAI_API_KEY, or remove the custom baseURL\n  throw new Error(\"Refusing OAuth token to custom endpoint; configure an API key\");\n}","typeGuard":"const isCredentialLeakGuard = (e: unknown): e is SearchProviderError =>\n  e instanceof SearchProviderError && e.message.includes(\"Refusing to send official xAI OAuth credentials\");","tryCatchPattern":"try {\n  result = await searchXAI(params);\n} catch (err) {\n  if (isCredentialLeakGuard(err)) {\n    // reconfigure: store an API key for provider \"xai\" or \"xai-oauth\", then retry once\n    return searchXAI({ ...params /* with API-key auth */ });\n  }\n  throw err;\n}","preventionTips":["Never pair XAI_OAUTH_TOKEN/OAuth login with a custom baseURL in the same environment","Store an explicit API key in auth storage for the xai provider when using custom endpoints","Audit environment setup in CI: assert XAI_OAUTH_TOKEN is unset when a gateway baseURL is configured","Prefer provider \"xai\" (API key) for any proxy or OpenAI-compat gateway"],"tags":["credential-security","oauth","xai","config-mismatch"],"backgroundTag":"credential-leak-prevention","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}