{"record":{"id":"72a0827d8037484c","repo":"crowdsecurity/crowdsec","slug":"failed-to-extract-claims","errorCode":null,"errorMessage":"failed to extract claims","messagePattern":"failed to extract claims","errorType":"http","errorClass":null,"httpStatus":401,"severity":"error","filePath":"pkg/apiserver/controllers/v1/utils.go","lineNumber":41,"sourceCode":"\tif !ok {\n\t\treturn nil, errors.New(\"bouncer not found\")\n\t}\n\n\treturn bouncerInfo, nil\n}\n\nfunc isUnixSocket(c *gin.Context) bool {\n\tif localAddr, ok := c.Request.Context().Value(http.LocalAddrContextKey).(net.Addr); ok {\n\t\treturn strings.HasPrefix(localAddr.Network(), \"unix\")\n\t}\n\n\treturn false\n}\n\nfunc getMachineIDFromContext(ctx *gin.Context) (string, error) {\n\tclaims := jwt.ExtractClaims(ctx)\n\tif claims == nil {\n\t\treturn \"\", errors.New(\"failed to extract claims\")\n\t}\n\n\trawID, ok := claims[middlewares.MachineIDKey]\n\tif !ok {\n\t\treturn \"\", errors.New(\"MachineID not found in claims\")\n\t}\n\n\tid, ok := rawID.(string)\n\tif !ok {\n\t\t// should never happen\n\t\treturn \"\", errors.New(\"failed to cast machineID to string\")\n\t}\n\n\treturn id, nil\n}\n\nfunc (*Controller) AbortRemoteIf(option bool) gin.HandlerFunc {\n\treturn func(gctx *gin.Context) {","sourceCodeStart":23,"sourceCodeEnd":59,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/apiserver/controllers/v1/utils.go#L23-L59","documentation":"getMachineIDFromContext reads the JWT claims extracted by the gin-jwt middleware via jwt.ExtractClaims(ctx). It returns \"failed to extract claims\" when ExtractClaims returns nil, i.e. the request carries no usable JWT claim payload — typically because the JWT middleware never validated a token for this request.","triggerScenarios":"Handlers CreateAlert, HeartBeat, DeleteMachine, PrometheusMachinesMiddleware or UsageMetrics are reached without a validated machine JWT: missing/expired Authorization header, token rejected upstream but the request not aborted, or direct handler invocation in tests.","commonSituations":"A machine client whose token expired mid-request-batch; a reverse proxy stripping the Authorization header; calling LAPI endpoints with an API key instead of a machine JWT; unit tests calling handlers without authMiddleware.","solutions":["Ensure the JWT auth middleware runs and aborts unauthorized requests before these handlers","Re-authenticate the machine with `cscli machines add` / crowdsec LAPI login to obtain a fresh token","Verify the Authorization: Bearer header survives any proxy between agent and LAPI","In tests, seed the gin context with valid claims or run the auth middleware first"],"exampleFix":"// before: handler reachable without auth\nr.POST(\"/alerts\", ctrl.CreateAlert)\n// after\nr.POST(\"/alerts\", jwtMiddleware.MiddlewareFunc(), ctrl.CreateAlert)","handlingStrategy":"try-catch","validationCode":"hdr := c.GetHeader(\"Authorization\")\nif !strings.HasPrefix(hdr, \"Bearer \") || len(hdr) < 20 {\n    // request will not yield claims; reject early or force re-login\n}","typeGuard":"claims := jwt.ExtractClaims(c)\nif claims == nil { /* token missing or invalid — redirect to re-auth */ }","tryCatchPattern":"machineID, err := getMachineIDFromContext(c)\nif err != nil {\n    c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{\"message\": \"authentication required\"})\n    return\n}","preventionTips":["Ensure the JWT middleware aborts unauthenticated requests before handlers run","Refresh machine tokens before expiry (crowdsec handles this; don't strip Authorization at proxies)","In tests, invoke the auth middleware or inject claims before calling handlers"],"tags":["jwt","authentication","lapi","machine"],"backgroundTag":"authentication-required","analyzedSha":"909b5157986a2b2c2163300fdaef5ed01289f7d2","analyzedAt":"2026-09-06T12:27:26.012Z","contentChangedAt":"2026-09-06T12:27:26.012Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}