diff --git a/http_cache/form_csrf_caching.rst b/http_cache/form_csrf_caching.rst index 41aba4c0eab..abea53b988d 100644 --- a/http_cache/form_csrf_caching.rst +++ b/http_cache/form_csrf_caching.rst @@ -30,7 +30,44 @@ How to Cache Most of the Page and still be able to Use CSRF Protection To cache a page that contains a CSRF token, you can use more advanced caching techniques like :doc:`ESI fragments `, where you cache the full -page and embedding the form inside an ESI tag with no cache at all. +page and embedding the form or just the CSRF token inside an ESI tag with no +cache at all. When you have your custom form theme you can do this by create a +new token_widget block and call render_esi there: + +.. code-block:: twig + + {%- block token_widget %} + {{ render_esi(controller('App\\Controller\\FormController::token', { 'form': form.parent.vars.name })) }} + {%- endblock token_widget -%} + +You can use the ``security.csrf.token_manager`` service to generate a token for your given form: + +.. code-block:: php + + public function token(Request $request, TokenGeneratorInterface $generator) + { + $formName = $request->attributes->get('form'); + $csrfToken = $csrfTokenManager->getToken($formName)->getValue(); + + $response = new Response(sprintf( + '', + $formName, + $formName, + $csrfToken + )); + + // In some cases you have a response listener maybe which will set cache headers + // automatically most kind of this listener will not set it if cache headers exist + // so add the following if you want to be sure the response is not cached: + $response->setPrivate(); + $response->setSharedMaxAge(0); + $response->setMaxAge(0); + $response->headers->addCacheControlDirective('must-revalidate', true); + $response->headers->addCacheControlDirective('no-cache', true); + $response->headers->addCacheControlDirective('no-store', true); + + return $response; + } Another option would be to load the form via an uncached AJAX request, but cache the rest of the HTML response.