{"record":{"id":"5a07f027faaf9aa6","repo":"yikart/AiToEarn","slug":"token","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":52,"sourceCode":"   * @returns\n   */\n  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":34,"sourceCodeEnd":59,"githubUrl":"https://github.com/yikart/AiToEarn/blob/d3aa8bea5b146a8675607cf0144d891aad3e9683/project/aitoearn-electron/server/src/auth/auth.service.ts#L34-L59","documentation":"decodeToken strips the 'Bearer ' prefix and calls jwtService.decode; when decoding fails with TokenExpiredError it throws UnauthorizedException 'Token已过期，请重新登录'. The JWT is well-formed but its exp claim has passed, so it is no longer valid.","triggerScenarios":"Any authenticated Electron-server request whose Authorization header carries an expired JWT that reaches decodeToken.","commonSituations":"Client stayed logged in past token TTL; long-running Electron session without refresh; clock skew between client and server making tokens appear expired.","solutions":["Have the client refresh the token or re-login to obtain a new JWT.","Increase token TTL in JwtModule signOptions if sessions are too short.","Implement automatic token refresh on 401 in the client.","Check client clock sync if expiry seems premature."],"exampleFix":"// client before\nconst res = await fetch(url, { headers: { Authorization: token } });\n// after\nlet res = await fetch(url, { headers: { Authorization: token } });\nif (res.status === 401) {\n  token = await refreshToken();\n  res = await fetch(url, { headers: { Authorization: token } });\n}","handlingStrategy":"try-catch","validationCode":"function isTokenExpired(token) {\n  try {\n    const payload = JSON.parse(atob(token.replace('Bearer ', '').split('.')[1]));\n    return payload.exp * 1000 < Date.now();\n  } catch { return true; }\n}","typeGuard":null,"tryCatchPattern":"try {\n  await api.call(token);\n} catch (e) {\n  if (e?.response?.status === 401 && /Token已过期/.test(e.message)) {\n    token = await refreshOrRelogin();\n    await api.call(token);\n  } else throw e;\n}","preventionTips":["Implement proactive token refresh before exp (e.g., at 80% of TTL).","Treat 401 with 'Token已过期' as a refresh signal, not a fatal error.","Keep client clock reasonably synced (NTP).","Persist refresh tokens securely in the Electron app."],"tags":["jwt","auth","token-expired","http-401"],"backgroundTag":"jwt-token-expired","analyzedSha":"d3aa8bea5b146a8675607cf0144d891aad3e9683","analyzedAt":"2026-08-31T14:19:24.185Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}