{"record":{"id":"15c7496f568cdb2f","repo":"v2rayA/v2rayA","slug":"unauthorized","errorCode":"UNAUTHORIZED","errorMessage":"bad token: invalid claims","messagePattern":"bad token: invalid claims","errorType":"http","errorClass":null,"httpStatus":401,"severity":"error","filePath":"service/pkg/server/jwt/jwtTools.go","lineNumber":56,"sourceCode":"\t\t)\n\t\tif err != nil {\n\t\t\tif errors.Is(err, request.ErrNoTokenInRequest) {\n\t\t\t\ttoken, err = request.ParseFromRequest(ctx.Request, AuthorizationArgumentExtractor,\n\t\t\t\t\tfunc(token *jwt.Token) (interface{}, error) {\n\t\t\t\t\t\treturn getSecret(), nil\n\t\t\t\t\t},\n\t\t\t\t\trequest.WithParser(parser),\n\t\t\t\t)\n\t\t\t}\n\t\t\tif err != nil {\n\t\t\t\tcommon.Response(ctx, common.UNAUTHORIZED, err.Error())\n\t\t\t\tctx.Abort()\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t\tmapClaims, ok := token.Claims.(jwt.MapClaims)\n\t\tif !ok {\n\t\t\tcommon.ResponseError(ctx, errors.New(\"bad token: invalid claims\"))\n\t\t\tctx.Abort()\n\t\t\treturn\n\t\t}\n\t\texp, err := mapClaims.GetExpirationTime()\n\t\tif err == nil && exp != nil {\n\t\t\tif time.Now().After(exp.Time) {\n\t\t\t\tcommon.ResponseError(ctx, errors.New(\"expired token\"))\n\t\t\t\tctx.Abort()\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t\t//如果需要Admin权限\n\t\tif Admin {\n\t\t\tadminVal, _ := mapClaims[\"admin\"]\n\t\t\tif adminVal != true {\n\t\t\t\tcommon.ResponseError(ctx, errors.New(\"admin required\"))\n\t\t\t\tctx.Abort()\n\t\t\t\treturn","sourceCodeStart":38,"sourceCodeEnd":74,"githubUrl":"https://github.com/v2rayA/v2rayA/blob/71e5442fc548c05680ee55eae943e6c0afe9ac51/service/pkg/server/jwt/jwtTools.go#L38-L74","documentation":"The JWT middleware in service/pkg/server/jwt/jwtTools.go (JWTAuth) parses the bearer token from the Authorization header (or Argument header fallback) and then type-asserts token.Claims to jwt.MapClaims. If the assertion fails, it responds 'bad token: invalid claims' with an unauthorized error and aborts the request. This happens when the token parses and verifies cryptographically but its claims are not a JSON object map (e.g. a token whose claims are a struct or non-object JSON value).","triggerScenarios":"A request supplies a syntactically valid, correctly signed HS256 token whose claims payload is not a JSON object (e.g. the token body is a JSON array, string, or number), so token.Claims.(jwt.MapClaims) fails in the middleware at jwtTools.go:55.","commonSituations":"Tokens minted by a non-standard issuer or an older/different library that serializes claims as a non-map type; corrupted or hand-crafted tokens; mixing token formats between services after an API change.","solutions":["Re-mint the token with jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{...}) so claims are a JSON object (see MakeJWT in the same file)","Inspect the token payload (decode the middle JWT segment) and confirm it is a JSON object like {\"name\":...,\"exp\":...}","Ensure the client uses the token issued by this service's login endpoint rather than a token from another system"],"exampleFix":"// before: claims serialized as a non-map payload\ntok := jwt.NewWithClaims(jwt.SigningMethodHS256, myCustomStruct)\n// after: always use MapClaims so the middleware's assertion succeeds\nclaims := jwt.MapClaims{\"name\": \"alice\", \"exp\": jwt.NewNumericDate(time.Now().Add(time.Hour))}\ntok := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)","handlingStrategy":"type-guard","validationCode":"func claimsAreMap(token *jwt.Token) bool {\n    _, ok := token.Claims.(jwt.MapClaims)\n    return ok\n}\n// decode payload before sending:\n// parts := strings.Split(tokenString, \".\"); payload, _ := base64.RawURLEncoding.DecodeString(parts[1]); check payload starts with '{'","typeGuard":"func hasMapClaims(tok *jwt.Token) (jwt.MapClaims, bool) {\n    claims, ok := tok.Claims.(jwt.MapClaims)\n    return claims, ok && tok.Valid\n}","tryCatchPattern":"token, err := request.ParseFromRequest(req, request.AuthorizationHeaderExtractor, keyFunc)\nif err != nil {\n    // handle parse/signature errors\n} else if claims, ok := token.Claims.(jwt.MapClaims); !ok {\n    // treat as unauthorized: re-authenticate to get a MapClaims-based token\n}","preventionTips":["Always mint tokens with jwt.MapClaims, not custom claim types, when this middleware is in the path","Spot-check token payload decodes to a JSON object before deploying a new issuer","Keep token minting centralized in one helper (e.g. MakeJWT)"],"tags":["jwt","authentication","go","gin"],"backgroundTag":"jwt-invalid-claims","analyzedSha":"71e5442fc548c05680ee55eae943e6c0afe9ac51","analyzedAt":"2026-09-05T20:04:37.459Z","contentChangedAt":"2026-09-05T20:04:37.459Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}