{"record":{"id":"aa7f2e031eda8fbf","repo":"yikart/AiToEarn","slug":"token-aa7f2e","errorCode":null,"errorMessage":"Token校验失败，请重新登录","messagePattern":"Token校验失败，请重新登录","errorType":"http","errorClass":"UnauthorizedException","httpStatus":401,"severity":"error","filePath":"project/aitoearn-electron/server/src/auth/auth.service.ts","lineNumber":54,"sourceCode":"  async resetToken(tokenInfo: TokenInfo): Promise<string> {\n    const payload: TokenInfo = {\n      phone: tokenInfo.phone,\n      id: tokenInfo.id,\n      name: tokenInfo.name,\n      isManager: tokenInfo.isManager,\n    };\n    return this.jwtService.sign(payload);\n  }\n\n  async decodeToken(token: string): Promise<TokenInfo> {\n    token = token.replace('Bearer ', '');\n    try {\n      return this.jwtService.decode(token);\n    } catch (error) {\n      if (error.name === 'TokenExpiredError') {\n        throw new UnauthorizedException('Token已过期，请重新登录');\n      } else {\n        throw new UnauthorizedException('Token校验失败，请重新登录');\n      }\n    }\n  }\n}\n","sourceCodeStart":36,"sourceCodeEnd":59,"githubUrl":"https://github.com/yikart/AiToEarn/blob/d3aa8bea5b146a8675607cf0144d891aad3e9683/project/aitoearn-electron/server/src/auth/auth.service.ts#L36-L59","documentation":"The else branch of decodeToken: any decode error that is NOT TokenExpiredError becomes UnauthorizedException 'Token校验失败，请重新登录'. The token could not be validated/decoded at all — malformed structure, bad signature, or invalid format.","triggerScenarios":"Requests with a corrupted/truncated JWT, a token signed with a different AUTH_SECRET, garbage in the Authorization header after 'Bearer ', or a JsonWebTokenError during decode.","commonSituations":"Secret rotation between server deploys invalidating old tokens; client sending a raw token without 'Bearer ' handled correctly; token copied from another environment; AUTH_SECRET differing between instances.","solutions":["Re-login to get a fresh, correctly signed token.","Confirm AUTH_SECRET is identical across server instances/environments.","Inspect the Authorization header format: must be 'Bearer <jwt>'.","Decode the token at jwt.io to check its structure and signature."],"exampleFix":"// before\nconst token = localStorage.getItem('token');\n// after\nconst token = localStorage.getItem('token');\nif (!token || token.split('.').length !== 3) await relogin();","handlingStrategy":"try-catch","validationCode":"function isWellFormedJwt(token) {\n  const t = token.replace(/^Bearer\\s+/, '');\n  return typeof t === 'string' && t.split('.').length === 3 && t.length > 20;\n}","typeGuard":"function hasJwtShape(t) {\n  return typeof t === 'string' && t.split('.').length === 3;\n}","tryCatchPattern":"try {\n  await api.call(token);\n} catch (e) {\n  if (e?.response?.status === 401 && /Token校验失败/.test(e.message)) {\n    await relogin(); // token 结构/签名无效，必须重新登录\n  } else throw e;\n}","preventionTips":["Never hand-edit or truncate tokens; re-login instead.","Ensure AUTH_SECRET matches across environments before switching servers.","Always send the 'Bearer ' prefix exactly once.","On 401 with this message, re-login rather than retrying with the same token."],"tags":["jwt","auth","token-invalid","http-401"],"backgroundTag":"jwt-signature-verification-failed","analyzedSha":"d3aa8bea5b146a8675607cf0144d891aad3e9683","analyzedAt":"2026-08-31T14:19:24.185Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}