yikart/AiToEarn · error · UnauthorizedException

Token已过期,请重新登录

Error message

Token已过期,请重新登录

What it means

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.

Source

Thrown at project/aitoearn-electron/server/src/auth/auth.service.ts:52

   * @returns
   */
  async resetToken(tokenInfo: TokenInfo): Promise<string> {
    const payload: TokenInfo = {
      phone: tokenInfo.phone,
      id: tokenInfo.id,
      name: tokenInfo.name,
      isManager: tokenInfo.isManager,
    };
    return this.jwtService.sign(payload);
  }

  async decodeToken(token: string): Promise<TokenInfo> {
    token = token.replace('Bearer ', '');
    try {
      return this.jwtService.decode(token);
    } catch (error) {
      if (error.name === 'TokenExpiredError') {
        throw new UnauthorizedException('Token已过期,请重新登录');
      } else {
        throw new UnauthorizedException('Token校验失败,请重新登录');
      }
    }
  }
}

View on GitHub (pinned to d3aa8bea5b)

Solutions

  1. Have the client refresh the token or re-login to obtain a new JWT.
  2. Increase token TTL in JwtModule signOptions if sessions are too short.
  3. Implement automatic token refresh on 401 in the client.
  4. Check client clock sync if expiry seems premature.

Example fix

// client before
const res = await fetch(url, { headers: { Authorization: token } });
// after
let res = await fetch(url, { headers: { Authorization: token } });
if (res.status === 401) {
  token = await refreshToken();
  res = await fetch(url, { headers: { Authorization: token } });
}
Defensive patterns

Strategy: try-catch

Validate before calling

function isTokenExpired(token) {
  try {
    const payload = JSON.parse(atob(token.replace('Bearer ', '').split('.')[1]));
    return payload.exp * 1000 < Date.now();
  } catch { return true; }
}

Try / catch

try {
  await api.call(token);
} catch (e) {
  if (e?.response?.status === 401 && /Token已过期/.test(e.message)) {
    token = await refreshOrRelogin();
    await api.call(token);
  } else throw e;
}

Prevention

When it happens

Trigger: Any authenticated Electron-server request whose Authorization header carries an expired JWT that reaches decodeToken.

Common situations: Client stayed logged in past token TTL; long-running Electron session without refresh; clock skew between client and server making tokens appear expired.

Related errors


AI-assisted analysis of yikart/AiToEarn@d3aa8bea5b (2026-08-31). Data as JSON: /api/errors/5a07f027faaf9aa6. Report an issue: GitHub.