{"record":{"id":"57e0d38da8a459bf","repo":"fish2018/pansou","slug":"invalid-token","errorCode":null,"errorMessage":"invalid token","messagePattern":"invalid token","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"util/jwt.go","lineNumber":63,"sourceCode":"\t\treturn nil, errors.New(\"secret cannot be empty\")\n\t}\n\n\tclaims := &Claims{}\n\n\ttoken, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) {\n\t\t// 验证签名算法\n\t\tif _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {\n\t\t\treturn nil, errors.New(\"unexpected signing method\")\n\t\t}\n\t\treturn []byte(secret), nil\n\t})\n\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif !token.Valid {\n\t\treturn nil, errors.New(\"invalid token\")\n\t}\n\n\treturn claims, nil\n}\n","sourceCodeStart":45,"sourceCodeEnd":68,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/util/jwt.go#L45-L68","documentation":"After parsing, ValidateToken checks token.Valid; if the parser returned no error but the token is not valid (expired, malformed claims, failed validation), it returns this sentinel \"invalid token\" error.","triggerScenarios":"Validating an expired JWT (exp in the past), a token whose claims fail validation, or a tampered token that happens to parse but fails validity checks.","commonSituations":"Long-lived client sessions past expiry; clock skew between issuer and validator; user keeps using a token after secret rotation.","solutions":["Have the client obtain a fresh token via LoginHandler and retry","Check for expiry specifically (errors.Is(err, jwt.ErrTokenExpired) / validate errors) and return 401 prompting re-login","Implement token refresh so clients renew before expiry","Synchronize server clocks if skew is the cause"],"exampleFix":"// before\nclaims, err := util.ValidateToken(tokenString, secret)\nif err != nil { c.AbortWithStatusJSON(401, gin.H{\"error\": \"unauthorized\"}); return }\n// after\nclaims, err := util.ValidateToken(tokenString, secret)\nif err != nil {\n    c.AbortWithStatusJSON(401, gin.H{\"error\": \"invalid or expired token, please login again\"})\n    return\n}","handlingStrategy":"try-catch","validationCode":"// check expiry locally before calling API\nclaims, _, _ := parseUnverified(tokenString)\nif claims != nil && time.Now().After(claims.ExpiresAt.Time) { refreshToken() }","typeGuard":null,"tryCatchPattern":"claims, err := util.ValidateToken(tokenString, secret)\nif err != nil {\n    // treat as expired: redirect to login or refresh token\n    c.AbortWithStatusJSON(401, gin.H{\"error\": \"token expired\"})\n    return\n}","preventionTips":["Implement token refresh before expiry","Set reasonable expiry durations at issuance","Handle 401 by re-authenticating automatically"],"tags":["jwt","token-expired","authentication","go"],"backgroundTag":"jwt-token-expired","analyzedSha":"beaa56133755a548ebc51b090b3816e2ae044aa6","analyzedAt":"2026-09-07T00:31:18.025Z","contentChangedAt":"2026-09-07T00:31:18.025Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}