{"id":"7785a79e7c20f8de","repo":"gofiber/fiber","slug":"csrf-token-not-found","errorCode":null,"errorMessage":"csrf: token not found","messagePattern":"csrf: token not found","errorType":"validation","errorClass":"ErrTokenNotFound","httpStatus":null,"severity":"error","filePath":"middleware/csrf/csrf.go","lineNumber":23,"sourceCode":"\t\"fmt\"\n\t\"net/url\"\n\t\"slices\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/gofiber/utils/v2\"\n\tutilsstrings \"github.com/gofiber/utils/v2/strings\"\n\n\t\"github.com/gofiber/fiber/v3\"\n\t\"github.com/gofiber/fiber/v3/extractors\"\n\t\"github.com/gofiber/fiber/v3/internal/redact\"\n\t\"github.com/gofiber/fiber/v3/internal/schemehost\"\n\t\"github.com/gofiber/fiber/v3/middleware/logger\"\n)\n\nvar (\n\tErrTokenNotFound    = errors.New(\"csrf: token not found\")\n\tErrTokenInvalid     = errors.New(\"csrf: token invalid\")\n\tErrFetchSiteInvalid = errors.New(\"csrf: sec-fetch-site header invalid\")\n\tErrRefererNotFound  = errors.New(\"csrf: referer header missing\")\n\tErrRefererInvalid   = errors.New(\"csrf: referer header invalid\")\n\tErrRefererNoMatch   = errors.New(\"csrf: referer does not match host or trusted origins\")\n\tErrOriginInvalid    = errors.New(\"csrf: origin header invalid\")\n\tErrOriginNoMatch    = errors.New(\"csrf: origin does not match host or trusted origins\")\n\terrOriginNotFound   = errors.New(\"origin not supplied or is null\") // internal error, will not be returned to the user\n\tdummyValue          = []byte{'+'}                                  // dummyValue is a placeholder value stored in token storage. The actual token validation relies on the key, not this value.\n\n)\n\nvar registerLogContextTagsOnce sync.Once\n\n// Handler for CSRF middleware\ntype Handler struct {\n\tsessionManager *sessionManager\n\tstorageManager *storageManager","sourceCodeStart":5,"sourceCodeEnd":41,"githubUrl":"https://github.com/gofiber/fiber/blob/9a4c7e57fe0b080a04235d28a4b0d2b4b353d58c/middleware/csrf/csrf.go#L5-L41","documentation":"Returned by the CSRF middleware (csrf.go:23) when an unsafe HTTP method (POST, PUT, PATCH, DELETE, etc.) is received and the configured Extractor cannot find a CSRF token, or finds an empty string, or the token is not present in server-side storage (expired or never created). The middleware uses double-submit-cookie plus server-side storage validation, so the token must exist in the request payload/header AND in storage. Triggered from csrf.go:168, 175, 195, and 332.","triggerScenarios":"A state-changing request (POST/PUT/PATCH/DELETE) is sent without the CSRF token in the location the Extractor is configured to read (default: form field '_csrf' or header 'X-Csrf-Token'); or the token cookie expired; or the token was already consumed (SingleUseToken=true); or the client sent a token that was never issued by this server instance (e.g. after a restart with in-memory storage).","commonSituations":"Frontend SPA forgot to include the CSRF token header on a fetch POST; cookie was cleared; load-balanced deployment with in-memory storage where the token was issued by a different instance; token expired due to IdleTimeout; using SingleUseToken and the client retried a request.","solutions":["Ensure the frontend reads the CSRF token from the cookie/endpoint and sends it on every unsafe-method request via the configured header or form field.","If running multiple instances, configure a shared Storage (Redis, etc.) instead of the default in-memory storage so tokens are valid cluster-wide.","Increase IdleTimeout / Expiration if tokens expire too quickly for your users.","If SingleUseToken is enabled, ensure the client fetches a fresh token after each mutating request."],"exampleFix":"// before — fetch POST with no CSRF header\nfetch('/api/update', {method:'POST', credentials:'same-origin', body:data})\n// after — read token from cookie and send as header\nfunction getCookie(n){return document.cookie.match(n+'=([^;]+)')?.[1]}\nfetch('/api/update', {method:'POST', credentials:'same-origin',\n  headers:{'X-Csrf-Token': getCookie('csrf_')}, body:data})","handlingStrategy":"validation","validationCode":"// Frontend: ensure token is attached before sending unsafe requests\nfunction safeFetch(url, opts={}) {\n  if (['POST','PUT','PATCH','DELETE'].includes(opts.method)) {\n    opts.headers = opts.headers || {}\n    opts.headers['X-Csrf-Token'] = getCookie('csrf_')\n  }\n  return fetch(url, {credentials:'same-origin', ...opts})\n}","typeGuard":null,"tryCatchPattern":"// Customize the CSRF error handler to guide clients\napp.Use(csrf.New(csrf.Config{\n  ErrorHandler: func(c fiber.Ctx, err error) error {\n    if errors.Is(err, csrf.ErrTokenNotFound) {\n      return c.Status(403).JSON(fiber.Map{\"error\":\"CSRF token missing or expired. Fetch a new token.\"})\n    }\n    return c.Status(403).SendString(err.Error())\n  },\n}))","preventionTips":["Always fetch and attach the CSRF token on unsafe requests from the frontend.","Use shared Storage (Redis) in multi-instance deployments.","Increase IdleTimeout if users spend long periods on forms."],"tags":["csrf","security","authentication","middleware","web"],"analyzedSha":"9a4c7e57fe0b080a04235d28a4b0d2b4b353d58c","analyzedAt":"2026-08-04T21:44:03.395Z","schemaVersion":2}