Symfony: make CSRF token available to all templates on a branch
My app has AJAX requests here and there and I want to protect them with CSRF tokens. However, instead of generating and passing a CSRF token to a Twig renderer for use in JavaScript, I would like the CSRF token to be readily available on every html page that Twig renders.
I saw that Laravel seems to put it in a meta tag, so I can grab it easily with JavaScript. But how do you do this in Symfony? How can I insert this token into every page?
Or is this not good practice?
source to share
Of course this is good practice!
You have a built-in function csrf_token('key')
in symfony / twig to do this.
Example:
<a href="{{ path('product_remove', {id: product.id, csrf: csrf_token('product') }) }}"
class="btn btn-info">Remove</a>
From the controller, you just have to check it:
/**
* @Route("/product/remove/{csrf}/{id}", name="product_remove")
*/
public function removeProductAction($csrf, $id)
{
if ($csrf !== $this->get('security.csrf.token_manager')->getToken('product')->getValue()) {
throw new InvalidCsrfTokenException('Invalid CSRF token');
}
// delete $id
// cleans up url
return $this->redirectToRoute('product_list');
}
source to share
Answer: insert it as a global twig variable and then use Javascript to bind to all requests.
config.yml
twig:
## ...
globals:
csrfTokenManager: '@security.csrf.token_manager'
base.html.twig
<script>
$.ajaxSetup({
beforeSend: function(xhr) {
xhr.setRequestHeader('x-csrf-token', '{{ csrfTokenManager.getToken('ajaxAuth') }}');
});
</script>
Receiving controller
public function receiveAction (Request $request)
{
$tokenManager = $this->get('security.csrf.token_manager');
$tokenId = 'ajaxAuth';
$token = new CsrfToken($tokenId, $request->headers->get('x-csrf-token'));
if (!$tokenManager->isTokenValid($token)) {
throw new HttpException(403, 'Go away h4x0r');
}
}
source to share