{"record":{"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/dce7939f86fb283e167ad709955abedb7bf23124/src/cmap/auth/mongodb_oidc/automated_callback_workflow.ts#L63-L89","documentation":"Thrown by the OIDC automated (machine) callback workflow when the user-supplied OIDC_CALLBACK does not resolve within AUTOMATED_TIMEOUT_MS (60000 ms / 1 minute). The automated workflow aborts the callback's AbortController and rejects with a MongoOIDCError so the connection does not hang indefinitely.","triggerScenarios":"Registering OIDC_CALLBACK (machine flow) whose returned Promise takes longer than 60 seconds, or never resolves. Fires at automated_callback_workflow.ts:81 after the Promise.race with the Timeout resolves in favor of the timeout.","commonSituations":"Callback makes a slow HTTP request to a token endpoint behind a slow/unreachable network. Token endpoint is down and the callback has no timeout of its own. Deadlock or missed await inside the callback.","solutions":["Make the callback fast and resilient: cache the token internally and only refresh near expiry.","Add your own shorter timeout inside the callback so it rejects before 60s with a clear error.","Verify network reachability and credentials for the token endpoint the callback calls."],"exampleFix":"// before\nconst cb = async () => {\n  const r = await fetch(tokenUrl); // may hang forever\n  return { accessToken: (await r.json()).token };\n};\n// after\nconst cb = async (params) => {\n  const r = await fetch(tokenUrl, { signal: params.timeoutContext });\n  return { accessToken: (await r.json()).token };\n};","handlingStrategy":"try-catch","validationCode":"function makeCallback(inner) {\n  return async (params) => {\n    return await inner(params); // inner must respect params.timeoutContext\n  };\n}","typeGuard":null,"tryCatchPattern":"try {\n  await client.connect();\n} catch (e) {\n  if (e instanceof MongoOIDCError && /timed out/.test(e.message)) {\n    // inspect callback for blocking I/O; add internal caching/timeout\n  }\n  throw e;\n}","preventionTips":["Cache tokens inside the callback; refresh only near expiry.","Honor params.timeoutContext by passing it to fetch/AbortController.","Add your own sub-60s timeout so failures surface quickly."],"tags":["authentication","oidc","timeout","callback","performance"],"backgroundTag":null,"analyzedSha":"dce7939f86fb283e167ad709955abedb7bf23124","analyzedAt":"2026-08-11T04:54:53.215Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}