yikart/AiToEarn · warning · BadRequestException
无效的state参数
Error message
无效的state参数
What it means
The 'state' query parameter in the OAuth callback must be a URI-encoded JSON string containing originalState, userId and email. If decodeURIComponent(state) or JSON.parse fails, BadRequestException '无效的state参数' (invalid state parameter) is thrown.
Source
Thrown at project/aitoearn-electron/server/src/modules/plat/youtube/youtube.controller.ts:86
@Public()
@Get('auth/callback')
async handleAuthCallback(
// @GetToken() systemToken: TokenInfo,
@Query('code') code: string,
@Query('state') state: string,
// @Query('userId') userId: string,
@Res() res: Response
) {
if (!code || !state) {
throw new BadRequestException('授权参数不完整');
}
// 解析state参数以获取token
let stateData;
try {
stateData = JSON.parse(decodeURIComponent(state));
} catch (error) {
throw new BadRequestException('无效的state参数');
}
const { originalState, userId, email } = stateData;
// 现在您可以使用token变量
console.log('Retrieved userId and originalState:', userId, originalState, email);
try {
const results = await this.youtubeAuthService.handleAuthorizationCode(code, originalState, userId);
// 重定向到前端页面,带上token
// return res.redirect(`/auth/success?token=${token}`);
// return results
const render_msg = {
message: "授权成功! 这里是添加账号成功后的前端页面," ,
datas: results
};
return res.render('google/index', render_msg);View on GitHub (pinned to d3aa8bea5b)
Solutions
- When creating the auth URL, always URI-encode the JSON: encodeURIComponent(JSON.stringify({originalState, userId, email}))
- Log the received raw state value before parsing to spot encoding issues
- Ensure no middleware/proxy double-decodes the query string
- Align the state schema between the code that builds the URL and the callback handler
Example fix
// before
const state = JSON.stringify({ originalState, userId, email }); // raw JSON in URL
const url = `${authUrl}&state=${state}`;
// after
const state = encodeURIComponent(JSON.stringify({ originalState, userId, email }));
const url = `${authUrl}&state=${state}`; Defensive patterns
Strategy: type-guard
Validate before calling
const raw = decodeURIComponent(state);
const parsed = JSON.parse(raw); // wrap in try
if (!('originalState' in parsed) || !('userId' in parsed) || !('email' in parsed)) {
throw new Error('state JSON missing required fields');
} Type guard
function isValidState(v: unknown): v is { originalState: string; userId: string; email: string } {
return !!v && typeof v === 'object' &&
typeof (v as any).originalState === 'string' &&
typeof (v as any).userId === 'string' &&
typeof (v as any).email === 'string';
} Try / catch
try {
stateData = JSON.parse(decodeURIComponent(state));
if (!isValidState(stateData)) throw new Error('bad state schema');
} catch {
return res.status(400).send('invalid state');
} Prevention
- Always encodeURIComponent(JSON.stringify(state)) when building the auth URL
- Keep the state schema defined in one shared module for builder and parser
- Log the raw state on parse failure to diagnose encoding issues
- Avoid proxies that rewrite/re-decode query strings
When it happens
Trigger: The state value was double-encoded or not encoded at all so JSON.parse receives malformed input; a client modified/truncated the state; the callback is invoked manually with a non-JSON state value.
Common situations: Building the auth URL manually and passing JSON without encodeURIComponent (raw {,}," characters break parsing after framework decoding); passing state that was already decoded once by a proxy; frontend builds state differently than the callback expects (schema mismatch).
Related errors
- 授权参数不完整
- No response from Gemini
- ResponseCode.ChannelAuthSessionInvalid
- ResponseCode.ChannelAuthPlatformMismatch
- ResponseCode.ChannelAuthSessionCompleted
AI-assisted analysis of yikart/AiToEarn@d3aa8bea5b (2026-08-31).
Data as JSON: /api/errors/15a70756f6a1167d.
Report an issue: GitHub.