{"record":{"id":"397ce3c0d5fdc471","repo":"dotnet/aspnetcore","slug":"the-required-antiforgery-header-value-0-is-not","errorCode":null,"errorMessage":"The required antiforgery header value \"{0}\" is not present.","messagePattern":"The required antiforgery header value \"(.+?)\" is not present\\.","errorType":"validation","errorClass":"AntiforgeryValidationException","httpStatus":null,"severity":"error","filePath":"src/Antiforgery/src/Internal/DefaultAntiforgery.cs","lineNumber":162,"sourceCode":"\n        var tokens = await _tokenStore.GetRequestTokensAsync(httpContext);\n        if (tokens.CookieToken == null)\n        {\n            throw new AntiforgeryValidationException(\n                Resources.FormatAntiforgery_CookieToken_MustBeProvided(_options.Cookie.Name));\n        }\n\n        if (tokens.RequestToken == null)\n        {\n            if (_options.HeaderName == null)\n            {\n                var message = Resources.FormatAntiforgery_FormToken_MustBeProvided(_options.FormFieldName);\n                throw new AntiforgeryValidationException(message);\n            }\n            else if (!httpContext.Request.HasFormContentType)\n            {\n                var message = Resources.FormatAntiforgery_HeaderToken_MustBeProvided(_options.HeaderName);\n                throw new AntiforgeryValidationException(message);\n            }\n            else\n            {\n                var message = Resources.FormatAntiforgery_RequestToken_MustBeProvided(\n                    _options.FormFieldName,\n                    _options.HeaderName);\n                throw new AntiforgeryValidationException(message);\n            }\n        }\n\n        ValidateTokens(httpContext, tokens);\n\n        _logger.ValidatedAntiforgeryToken();\n    }\n\n    private void ValidateTokens(HttpContext httpContext, AntiforgeryTokenSet antiforgeryTokenSet)\n    {\n        Debug.Assert(!string.IsNullOrEmpty(antiforgeryTokenSet.CookieToken));","sourceCodeStart":144,"sourceCodeEnd":180,"githubUrl":"https://github.com/dotnet/aspnetcore/blob/3600ca084e9c8b5f4174fc5e747f4c52d2100806/src/Antiforgery/src/Internal/DefaultAntiforgery.cs#L144-L180","documentation":"Thrown during antiforgery validation when the application has configured a HeaderName (header-based token lookup) but the incoming request does not have a form content type. Because there is no form, the validator expects the token in the configured header; if the header is also absent, validation fails. This is the AJAX/SPA-style antiforgery path.","triggerScenarios":"AntiforgeryOptions.HeaderName is set (non-null) and ValidateAsync runs on a request whose Content-Type is not a form (e.g. application/json) and whose headers do not carry the configured RequestVerificationToken header.","commonSituations":"SPA calling a JSON endpoint without attaching the antiforgery header; renaming HeaderName on the server but not the client; sending a header but mis-cased or missing after a reverse proxy strips it; CORS preflight not forwarding the custom header.","solutions":["Have the client send the token in the configured header (default after setting options.HeaderName), e.g. headers['RequestVerificationToken'] = token read from the cookie or a hidden field.","Confirm the request actually reaches the server with the header attached (check browser Network tab and any proxy CORS allowed-headers).","Ensure AntiforgeryOptions.HeaderName matches on both server and client.","If you intend form-based validation instead, leave HeaderName null and post the token as a form field."],"exampleFix":"// before: header configured but not sent\nservices.AddAntiforgery(o => o.HeaderName = \"X-CSRF-TOKEN\");\nawait fetch('/api/data', { method:'POST', headers:{'Content-Type':'application/json'} });\n\n// after: send token in the configured header\nconst token = getCookie('Antiforgery'); // or read hidden field\nawait fetch('/api/data', {\n  method:'POST',\n  headers:{ 'Content-Type':'application/json', 'X-CSRF-TOKEN': token },\n  body: JSON.stringify(payload)\n});","handlingStrategy":"validation","validationCode":"// On the client, before POSTing to a header-protected endpoint:\nif (!request.headers.has(options.HeaderName)) { request.headers.set(options.HeaderName, getToken()); }","typeGuard":null,"tryCatchPattern":"try { await antiforgery.ValidateRequestAsync(httpContext); }\ncatch (AntiforgeryValidationException ex) { logger.LogWarning(ex, \"Antiforgery header missing\"); return Results.BadRequest(); }","preventionTips":["Centralize attaching the antiforgery header in a fetch wrapper/interceptor.","Ensure CORS allows the custom header through proxies.","Document the chosen HeaderName in the API contract.","Add a unit test that asserts a request without the header yields 400."],"tags":["antiforgery","aspnetcore","security","csrf","ajax","spa"],"backgroundTag":null,"analyzedSha":"3600ca084e9c8b5f4174fc5e747f4c52d2100806","analyzedAt":"2026-08-11T16:32:30.678Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}