CSRF tokens, and what “CSRF verification failed” means

A CSRF token is a secret, unpredictable value that a site puts into its own forms and checks when they come back. A forged request from another site cannot include it, because the attacker cannot read your pages. When the check fails, frameworks refuse the request with errors such as “CSRF token missing” or “CSRF verification failed”, and most of those failures are caused by sessions and cookies, not by attacks.

Section Web attacks Updated Defends against CSRF

Quick facts

Also called
Anti-CSRF token, anti-forgery token, synchronizer token, XSRF token
What it proves
That the request was built by a page your site served to this session
Where it travels
A hidden form field or a request header, never only in a cookie
Typical error
403 with “CSRF token missing” or “CSRF verification failed”
Most common cause of errors
An expired session, blocked cookies, or a cached page with an old token

Patterns follow the OWASP CSRF Prevention Cheat Sheet. The attack itself is on CSRF.

How a CSRF token works

  1. The server creates a token. Random, long enough not to be guessed, and tied to the user's session.
  2. It is placed in the page. As a hidden field in each form, or exposed for scripts to send in a header.
  3. The browser sends it back. With the form submission or the request.
  4. The server compares. If the token is missing or does not match the session, the request is refused.

The protection rests on one fact: another site can make the browser send a request, but cannot read your page to learn the token. That is also why a cross-site scripting flaw defeats it.

TOKEN PATTERNS COMPARED STORED ON THE SERVER TIED TO THE SESSION STOPS FORGERY SYNCHRONIZER TOKEN SIGNED DOUBLE-SUBMIT COOKIE PLAIN DOUBLE-SUBMIT COOKIE TOKEN ONLY IN A COOKIE // a token the browser sends on its own proves nothing
// four patterns, and which of them actually stop a forged request

Synchronizer tokens and double-submit cookies

A synchronizer token is stored on the server with the session and compared on each request. It is the simplest pattern to reason about and the one most frameworks use by default.

A double-submit cookie avoids server storage: the same value goes in a cookie and in the request, and the server checks they match. OWASP recommends the signed variant, where the value is bound to the session with a secret, because a plain version can be defeated by anyone who can set a cookie for your domain, for example from a subdomain.

“CSRF token missing” and “CSRF verification failed”: how to fix

If you are a visitor and see one of these errors, reload the page, sign in again, allow cookies for the site and submit the form once more. The usual cause is a page left open long enough for the session to expire.

If you run the site, check these in order. The Django CSRF documentation describes the same causes for its own “CSRF verification failed. Request aborted.” page.

  1. The form does not include the token. A template or a hand-written form skipped the hidden field.
  2. Scripts do not send the header. An API call from the page needs the token added to the request.
  3. The cookie is not sent. A SameSite, Secure or domain setting stops the cookie on this request; see Set-Cookie on MDN.
  4. The page was cached. A cached form carries a token from someone else's or an expired session.
  5. The origin check fails. A proxy or load balancer changes the host or scheme the framework expects.

What not to do with CSRF tokens

  • Do not switch the check off to make the error go away. Exempt a route only when it has other proof of intent, such as an API key in a header.
  • Do not put the token in a URL. It leaks through logs, history and the Referer header.
  • Do not reuse one token for every user. A shared value proves nothing.

A request filter in front of the site does not replace any of this; the forged request looks legitimate. See what a WAF can do about CSRF.

Questions

What is a CSRF token?

A CSRF token is a secret, unpredictable value tied to a user's session that a site places in its own forms and checks on submission, so requests forged by other sites are refused.

Why do I get “CSRF verification failed”?

Usually because the session expired, cookies are blocked, or the page was cached with an old token. Reloading the page, signing in again and allowing cookies fixes it for visitors.

Is a CSRF token still needed with SameSite cookies?

Yes, as the core defence. SameSite cookies add depth but do not cover same-site subdomains or every browser.

Where should a CSRF token be stored?

On the server with the session, or signed and bound to the session; it is sent in a hidden form field or request header, never only in a cookie or in the URL.