{"record":{"id":"738534458d24b8f9","repo":"mastra-ai/mastra","slug":"openai-codex-oauth-is-only-available-in-node-js-en","errorCode":null,"errorMessage":"OpenAI Codex OAuth is only available in Node.js environments","messagePattern":"OpenAI Codex OAuth is only available in Node\\.js environments","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"mastracode/sdk/src/auth/providers/openai-codex.ts","lineNumber":217,"sourceCode":"    if (!response.ok) {\n      const text = await response.text().catch(() => '');\n      console.error('[openai-codex] Token refresh failed:', response.status, text);\n      return { type: 'failed' };\n    }\n\n    return tokenResponseToResult((await response.json()) as TokenResponseJson, 'Token refresh');\n  } catch (error) {\n    console.error('[openai-codex] Token refresh error:', error);\n    return { type: 'failed' };\n  }\n}\n\nasync function getRandomBytes() {\n  if (!_randomBytes && _cryptoPromise) {\n    _randomBytes = (await _cryptoPromise).randomBytes;\n  }\n  if (!_randomBytes) {\n    throw new Error('OpenAI Codex OAuth is only available in Node.js environments');\n  }\n  return _randomBytes;\n}\n\nasync function createAuthorizationFlow(\n  redirectUri: string,\n  state: string,\n  originator: string = 'mastracode',\n): Promise<{ verifier: string; url: string }> {\n  const { verifier, challenge } = await generatePKCE();\n\n  const url = new URL(AUTHORIZE_URL);\n  url.searchParams.set('response_type', 'code');\n  url.searchParams.set('client_id', CLIENT_ID);\n  url.searchParams.set('redirect_uri', redirectUri);\n  url.searchParams.set('scope', SCOPE);\n  url.searchParams.set('code_challenge', challenge);\n  url.searchParams.set('code_challenge_method', 'S256');","sourceCodeStart":199,"sourceCodeEnd":235,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/mastracode/sdk/src/auth/providers/openai-codex.ts#L199-L235","documentation":"The OpenAI Codex OAuth provider needs Node's crypto.randomBytes to generate the PKCE code verifier, but the lazily-resolved crypto import failed (e.g. dynamic import of 'node:crypto' rejected in a non-Node runtime). The library throws this to stop the browser-style OAuth flow in environments that cannot supply Node crypto. It is a hard environment gate, not a transient fault.","triggerScenarios":"Calling loginOpenAICodex / createAuthorizationFlow (which calls getRandomBytes for PKCE generation) in a browser, edge worker (Cloudflare Workers, Vercel Edge), Deno/Bun without node:crypto compat, or a bundler that tree-shakes/stubs node:crypto so the dynamic import resolves without randomBytes.","commonSituations":"Running mastracode SDK code inside an edge runtime or serverless worker instead of a Node server; bundling with a browser target that aliases node:crypto; misconfigured test environment (jsdom/happy-dom) that lacks Node crypto globals; importing the provider into client-side code.","solutions":["Run the OAuth login flow in a Node.js runtime (>= 18), not in a browser or edge environment.","If bundling, configure your bundler to keep node:crypto as an external/builtin (e.g. external: ['node:crypto'] in esbuild, resolve fallbacks off in webpack) instead of polyfilling it away.","Switch tests/CI jobs that exercise OAuth to the node test environment (vitest environment: 'node') rather than jsdom.","If the target platform truly cannot use Node crypto, use the device-authorization login path (loginOpenAICodexDevice) which uses fetch instead."],"exampleFix":"// before: edge function that imports the provider\nexport const config = { runtime: 'edge' };\nimport { loginOpenAICodex } from 'mastracode/sdk';\n\n// after: run login in a Node route\n// next.config route on the Node.js runtime\nexport const config = { runtime: 'nodejs' };\nimport { loginOpenAICodex } from 'mastracode/sdk';","handlingStrategy":"validation","validationCode":"import { createRequire } from 'module';\nfunction canRunCodexOAuth(): boolean {\n  try {\n    const crypto = createRequire(import.meta.url)('node:crypto');\n    return typeof crypto.randomBytes === 'function';\n  } catch {\n    return false;\n  }\n}\nif (!canRunCodexOAuth()) useDeviceLoginInstead();","typeGuard":null,"tryCatchPattern":"try {\n  await loginOpenAICodex({});\n} catch (e) {\n  if (e.message.includes('only available in Node.js')) {\n    await loginOpenAICodexDevice({}); // fetch-based fallback\n  } else throw e;\n}","preventionTips":["Only import/invoke the OAuth provider from Node.js entry points.","Keep node: builtins external in bundler configs.","Use vitest environment 'node' for auth tests.","Prefer the device-login flow in edge/serverless targets."],"tags":["oauth","environment","nodejs","crypto"],"backgroundTag":"node-only-module-in-browser","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T08:17:16.595Z"}