{"id":"665986603799ccc3","repo":"mongodb/node-mongodb-native","slug":"oidc-callback-timed-out-after-automated-timeout","errorCode":null,"errorMessage":"OIDC callback timed out after ${AUTOMATED_TIMEOUT_MS}ms.","messagePattern":"OIDC callback timed out after (.+?)ms\\.","errorType":"exception","errorClass":"MongoOIDCError","httpStatus":null,"severity":"error","filePath":"src/cmap/auth/mongodb_oidc/automated_callback_workflow.ts","lineNumber":81,"sourceCode":"  protected async fetchAccessToken(credentials: MongoCredentials): Promise<OIDCResponse> {\n    const controller = new AbortController();\n    const params: OIDCCallbackParams = {\n      timeoutContext: controller.signal,\n      version: OIDC_VERSION\n    };\n    if (credentials.username) {\n      params.username = credentials.username;\n    }\n    if (credentials.mechanismProperties.TOKEN_RESOURCE) {\n      params.tokenAudience = credentials.mechanismProperties.TOKEN_RESOURCE;\n    }\n    const timeout = Timeout.expires(AUTOMATED_TIMEOUT_MS);\n    try {\n      return await Promise.race([this.executeAndValidateCallback(params), timeout]);\n    } catch (error) {\n      if (TimeoutError.is(error)) {\n        controller.abort();\n        throw new MongoOIDCError(`OIDC callback timed out after ${AUTOMATED_TIMEOUT_MS}ms.`);\n      }\n      throw error;\n    } finally {\n      timeout.clear();\n    }\n  }\n}\n","sourceCodeStart":63,"sourceCodeEnd":89,"githubUrl":"https://github.com/mongodb/node-mongodb-native/blob/3366c21a6311e02f1be91da982f9b93d3cce99a0/src/cmap/auth/mongodb_oidc/automated_callback_workflow.ts#L63-L89","documentation":"Thrown by the automated (machine) OIDC callback workflow when the OIDC callback function does not return within AUTOMATED_TIMEOUT_MS (60000ms / 1 minute) - see src/cmap/auth/mongodb_oidc/automated_callback_workflow.ts:81 and callback_workflow.ts:20. The driver aborts the callback via AbortController and surfaces this as a MongoOIDCError. The automated workflow is used for non-interactive (machine) environments like Azure/GCP/k8s/test.","triggerScenarios":"Calling MongoClient.connect with MONGODB-OIDC and ENVIRONMENT set to azure/gcp/k8s/test, or a custom automated callback, where the callback takes longer than 60 seconds to resolve. Also triggered if the callback hangs on a network call that ignores the provided timeoutContext (AbortSignal).","commonSituations":"The metadata endpoint (Azure IMDS, GCP metadata, k8s token file) is slow or unreachable, a custom machine callback performs slow synchronous work without honoring the AbortSignal, or the network to the cloud metadata service is blocked/firewalled causing the callback to spin.","solutions":["Ensure the cloud metadata endpoint is reachable from the host (Azure IMDS 169.254.169.254, GCP metadata.google.internal, k8s service account token file).","In a custom automated callback, honor params.timeoutContext: abort outstanding HTTP requests when the signal aborts and resolve quickly.","Reduce callback latency (avoid extra round trips, cache tokens within their lifetime).","If 60s is genuinely too short for your IdP, switch to a workflow that uses a faster token source or pre-fetch the token."],"exampleFix":"// before: callback ignores the abort signal\nconst cb = async (params) => {\n  const r = await fetch(idpUrl); // may hang indefinitely\n  return { accessToken: await r.json() };\n};\n\n// after: callback honors timeoutContext\nconst cb = async (params) => {\n  const r = await fetch(idpUrl, { signal: params.timeoutContext });\n  return { accessToken: (await r.json()).token };\n};","handlingStrategy":"validation","validationCode":"function assertOidcAutomatedCallbackReady(callback: (p: any) => Promise<any>): void {\n  // Smoke test the callback resolves quickly with a dummy AbortSignal\n  const ac = new AbortController();\n  const t = setTimeout(() => ac.abort(), 5000);\n  callback({ timeoutContext: ac.signal, version: 1 })\n    .then(r => { if (!r?.accessToken) console.warn('OIDC callback returned no accessToken'); })\n    .catch(e => console.warn('OIDC callback smoke test failed', e))\n    .finally(() => clearTimeout(t));\n}","typeGuard":null,"tryCatchPattern":"try {\n  await client.connect();\n} catch (e) {\n  if (e instanceof MongoOIDCError && /OIDC callback timed out/.test(e.message)) {\n    // Check metadata endpoint reachability, then retry with backoff\n    log.warn('OIDC automated callback timed out; verify metadata endpoint');\n  }\n  throw e;\n}","preventionTips":["Confirm the cloud metadata endpoint (169.254.169.254 / metadata.google.internal) is reachable before app start.","Always honor params.timeoutContext (AbortSignal) in custom callbacks.","Keep machine callback logic minimal - fetch token and return."],"tags":["auth","oidc","timeout","azure","gcp","k8s"],"analyzedSha":"3366c21a6311e02f1be91da982f9b93d3cce99a0","analyzedAt":"2026-08-04T13:40:15.335Z","schemaVersion":2}