{"record":{"id":"e8e908a94fa79a03","repo":"chatboxai/chatbox","slug":"minimax-oauth-state-mismatch","errorCode":null,"errorMessage":"MiniMax OAuth state mismatch","messagePattern":"MiniMax OAuth state mismatch","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/main/oauth/providers/minimax.ts","lineNumber":121,"sourceCode":"          state,\n        }).toString(),\n      })\n\n      if (!response.ok) {\n        const text = await response.text()\n        throw new Error(`MiniMax authorization failed: ${text}`)\n      }\n\n      const payload = (await response.json()) as {\n        user_code: string\n        verification_uri: string\n        expired_in?: number\n        interval?: number\n        state: string\n      }\n\n      if (payload.state !== state) {\n        throw new Error('MiniMax OAuth state mismatch')\n      }\n\n      pendingUserCode = payload.user_code\n      pendingVerifier = verifier\n      pendingIntervalMs = toPollingIntervalMs(payload.interval)\n\n      return {\n        userCode: payload.user_code,\n        verificationUri: payload.verification_uri,\n      }\n    },\n\n    async waitForToken(signal?: AbortSignal) {\n      if (!pendingUserCode || !pendingVerifier) {\n        throw new Error('No pending device flow. Call startDeviceFlow first.')\n      }\n\n      const userCode = pendingUserCode","sourceCodeStart":103,"sourceCodeEnd":139,"githubUrl":"https://github.com/chatboxai/chatbox/blob/81571269addb6bafb589a920b2883f1e1e084fd1/src/main/oauth/providers/minimax.ts#L103-L139","documentation":"Thrown in MiniMax startDeviceFlow() when the state echoed in the /oauth/code response does not equal the random state that was sent in the request body. This is a CSRF/response-integrity check: MiniMax is expected to echo the exact state. A mismatch suggests the response was fabricated, replayed from a different session, or the endpoint does not echo state as assumed.","triggerScenarios":"Two concurrent startDeviceFlow calls sharing module state and crossing responses; a proxy or middleware rewriting or caching the response; MiniMax backend change that no longer echoes the sent state; the response is from a different queued request.","commonSituations":"Race between two login windows on the same provider; misbehaving CDN cache returning a stale /oauth/code response; backend bug returning an empty or fixed state field.","solutions":["Treat a state mismatch as a security failure — do not proceed; abort and restart startDeviceFlow.","Serialize device-flow starts per provider so module-level pendingVerifier/state cannot cross between concurrent calls.","If reproducible, log both sent and received state to determine whether MiniMax stopped echoing it, then adjust the contract deliberately (not by ignoring the check)."],"exampleFix":"// before\nif (payload.state !== state) {\n  throw new Error('MiniMax OAuth state mismatch')\n}\n\n// after\nif (payload.state !== state) {\n  log.error('[OAuth:MiniMax] state mismatch', 'sent=', state, 'recv=', payload.state)\n  throw new SecurityError('MiniMax OAuth state mismatch — possible CSRF, retry the login')\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  return await provider.startDeviceFlow()\n} catch (e) {\n  if (/state mismatch/i.test(String(e))) {\n  // security-relevant: do not retry with same state; restart fresh\n  throw new SecurityError('MiniMax state mismatch — possible CSRF; restart login.')\n  }\n  throw e\n}","preventionTips":["Serialize startDeviceFlow calls per provider to prevent state crossing between concurrent flows.","Never disable or weaken the state check even if it fires sporadically — investigate the root cause.","Log both sent and received state on mismatch to detect backend or proxy tampering."],"tags":["oauth","security","csrf","state","minimax"],"backgroundTag":null,"analyzedSha":"81571269addb6bafb589a920b2883f1e1e084fd1","analyzedAt":"2026-08-12T21:51:44.981Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}