Secure actions on your website with Symfony2 and CSRF

How to make use POST method with CSRF token for simple actions like deleting a comment, or a simple-click action.

Sometimes, it may be hard to secure some actions on website. Here are some few examples where creating a form is clearly overkill. Those simple actions should be secured.

  • disable, validate, delete a comment
  • enable an account
  • logout
  • send e-mail

symfony 1.4 legacy

In symfony 1.4, it was possible to secure a link with a POST method, using helper link_to. This helper was used like this:

echo link_to('@route', array('sf_method' => 'POST'), 'your text);

Easy, isn't it? This helper created a Javascript function to post form:

  onclick="var f = document.createElement('form'); = 'none'; this.parentNode.appendChild(f); f.method = 'post'; f.action = this.href"
  >your text</a

See code on github for more details :

POST a link with jQuery

Add this snippet to your javascript library. Make it included on page rendering:

 * Sample usage:
 * <a href="/blog/48/delete" data-method="POST">delete this post</a>
$(document).ready(function () {
  // Every link with an attribute data-method
  $("a[data-method]").click(function (event) {

    var target = $(event.currentTarget);
    var method = target.attr("data-method");
    var action = target.attr("href");

    // Create a form on click
    var form = $("<form/>", {
      style: "display:none;",
      method: method,
      action: action,


    // Submit the form

And in your template:

  href="{{ path('message_delete', {id:, token: token}) }}"

Simple CSRF in Symfony2

Finally, we need to pass a token value to the template and check it:

// src/Acme/DemoBundle/Controller/MessageController.php

public function listAction()
    $token = $this->get('form.csrf_provider')->generateCsrfToken('message_list');

    return $this->render('AcmeDemoBundle:Message:list.html.twig', array(
        'token'    => $token,
        'messages' => array() // put your business here

public function deleteAction()
    if (!$this->get('form.csrf_provider')->isCsrfTokenValid($intention, $token)) {
        $this->get('session')->setFlash('notice', 'Woops! Token invalid!');

        return $this->redirect('message_list');

    return $this->render('AcmeDemoBundle:Message:list.html.twig', array(
        'token'    => $token,
        'messages' => array() // put your business here

Constraint routing

If you don't change your routing, this deleteAction method will allow POST and GET requests. You need to change your routing and add a requirement on method:

# routing.yml
  pattern: /message/{id}/delete
  requirements: { _method: POST }