chatboxai/chatbox · error · Error
MiniMax OAuth state mismatch
Error message
MiniMax OAuth state mismatch
What it means
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.
Source
Thrown at src/main/oauth/providers/minimax.ts:121
state,
}).toString(),
})
if (!response.ok) {
const text = await response.text()
throw new Error(`MiniMax authorization failed: ${text}`)
}
const payload = (await response.json()) as {
user_code: string
verification_uri: string
expired_in?: number
interval?: number
state: string
}
if (payload.state !== state) {
throw new Error('MiniMax OAuth state mismatch')
}
pendingUserCode = payload.user_code
pendingVerifier = verifier
pendingIntervalMs = toPollingIntervalMs(payload.interval)
return {
userCode: payload.user_code,
verificationUri: payload.verification_uri,
}
},
async waitForToken(signal?: AbortSignal) {
if (!pendingUserCode || !pendingVerifier) {
throw new Error('No pending device flow. Call startDeviceFlow first.')
}
const userCode = pendingUserCodeView on GitHub (pinned to 81571269ad)
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).
Example fix
// before
if (payload.state !== state) {
throw new Error('MiniMax OAuth state mismatch')
}
// after
if (payload.state !== state) {
log.error('[OAuth:MiniMax] state mismatch', 'sent=', state, 'recv=', payload.state)
throw new SecurityError('MiniMax OAuth state mismatch — possible CSRF, retry the login')
} Defensive patterns
Strategy: try-catch
Try / catch
try {
return await provider.startDeviceFlow()
} catch (e) {
if (/state mismatch/i.test(String(e))) {
// security-relevant: do not retry with same state; restart fresh
throw new SecurityError('MiniMax state mismatch — possible CSRF; restart login.')
}
throw e
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- OAuth state mismatch
- MiniMax authorization failed: ${text}
- MiniMax OAuth failed: ${errorMessage || text}
- MiniMax OAuth timed out waiting for authorization.
- Token refresh failed: ${text}
AI-assisted analysis of chatboxai/chatbox@81571269ad (2026-08-12).
Data as JSON: /api/errors/e8e908a94fa79a03.
Report an issue: GitHub.