Skip to content

Commit d776484

Browse files
committed
docs: carry the stateless CSRF section over to the 3.0 versioned docs
1 parent ee87f88 commit d776484

1 file changed

Lines changed: 29 additions & 0 deletions

File tree

  • versioned_docs/version-3.0/reference

versioned_docs/version-3.0/reference/forms.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,35 @@ Forms include CSRF protection by default. Always include hidden fields in your t
185185
{{ form_end(form) }}
186186
```
187187

188+
### Session-bound or stateless tokens
189+
190+
By default a `BaseForm` token is bound to the visitor's session: it is generated once, stored in the session and compared on submit. This is the right choice for forms that are always rendered fresh (account pages, checkout steps).
191+
192+
A form rendered inside a **cache** must not use a session token: a Turbo Drive snapshot, a Varnish page cache, a Twig fragment cache or an ESI block will replay a token that belongs to another session, and the submit fails with `The CSRF token is invalid`. For those forms, switch to Symfony's stateless validation, which checks the request origin (`Sec-Fetch-Site`, `Origin` or `Referer`) instead of a stored value. A stateless form renders a constant token, so the cached HTML stays valid for every visitor.
193+
194+
Two ways to opt in:
195+
196+
- pass a stateless token id when creating the form:
197+
198+
```php
199+
$form = $this->createForm(CartAdd::class, options: ['csrf_token_id' => 'submit']);
200+
```
201+
202+
`submit`, `authenticate` and `logout` are declared stateless by the `config/packages/csrf.yaml` that the framework-bundle recipe installs in every project.
203+
204+
- or declare the form's own name as stateless, without touching any PHP code. This is how a theme marks the forms it renders in cacheable zones:
205+
206+
```yaml
207+
# config/packages/csrf.yaml
208+
framework:
209+
csrf_protection:
210+
stateless_token_ids:
211+
- thelia_cart_add
212+
- thelia_coupon_code
213+
```
214+
215+
Session-bound tokens stay the default. `'csrf_protection' => false` still disables the protection entirely; prefer a stateless id over disabling it.
216+
188217
## Next steps
189218

190219
- [Front-Office Forms](/docs/front-office/forms) - LiveComponent forms with real-time validation

0 commit comments

Comments
 (0)