Documentation menu
On this page
Components · v1.x
Csrf
The Csrf component protects requests against cross-site request forgery with tokens stored in the session.
Tokens are masked differently every time they are rendered, and can be checked in forms, controllers or with the #[Csrf] attribute.
Tokens
A token is identified by a string id (contact, delete-post-42). It is created on first use and stored in the session; the same id gives a token valid until it is refreshed or removed.
In templates
| Helper | Returns |
|---|---|
csrf_token($id) |
a masked token |
csrf_field($id, $field = null) |
a hidden input (_token by default), safe HTML |
<form method="post" action="{{ path('post_delete', {id: post.id}) }}">
<input type="hidden" name="_token" value="{{ csrf_token('delete-post-' ~ post.id) }}">
<button>Delete</button>
</form>
<form method="post">
{{ csrf_field('contact') }}
</form>
<?= $this->csrf_field('contact') ?>
<input type="hidden" name="_token" value="<?= $this->e($this->csrf_token('delete-post-' . $post->getId())) ?>">
In controllers
public function delete(int $id, Request $request): Response
{
if (!$this->isCsrfTokenValid('delete-post-' . $id, $request->request->get('_token'))) {
throw $this->createAccessDeniedException();
}
return $this->redirectToRoute('post_index');
}
getCsrfToken($id) returns a token. Outside controllers, inject NeoPHP\Component\Csrf\Contract\CsrfInterface.
Csrf attribute
#[Csrf] (NeoPHP\Component\Csrf\Attribute\Csrf) on a controller class or a method checks the token of the POST, PUT, PATCH and DELETE requests before the controller (it is a route middleware, handled by CsrfMiddleware). A missing or invalid token throws an InvalidCsrfTokenException (HTTP 403). {id} placeholders are replaced by the route parameters. The token is read from the header X-CSRF-TOKEN (AJAX requests), then from the field _token.
<?php
declare(strict_types=1);
namespace App\Controller;
use App\Entity\Post;
use NeoPHP\Component\Controller\Contract\AbstractController;
use NeoPHP\Component\Csrf\Attribute\Csrf;
use NeoPHP\Component\Http\Response\Response;
use NeoPHP\Component\Routing\Attribute\Route;
class PostController extends AbstractController
{
#[Route('/posts/{id}/delete', name: 'post_delete', methods: ['POST'])]
#[Csrf('delete-post-{id}')]
public function delete(int $id): Response
{
$post = $this->getRepository(Post::class)->find($id) ?? throw $this->createNotFoundException();
$this->getOrm()->remove($post);
$this->getOrm()->flush();
return $this->redirectToRoute('post_index');
}
}
A route parameter is not converted into an entity: type the parameter int $id and load the entity with find().
| Option | Default |
|---|---|
id |
required; {parameter} placeholders are replaced by the route parameters |
field |
_token (field_name) |
header |
X-CSRF-TOKEN (header_name) |
methods |
['POST', 'PUT', 'PATCH', 'DELETE'] |
fetch('/posts/42/delete', { method: 'POST', headers: { 'X-CSRF-TOKEN': token } });
Forms
A hidden field _token is added to every form and checked by isValid() (error The CSRF token is invalid. Please try to resubmit the form.). Disable it with the form option 'csrf_protection' => false (API forms). The token id is the name of the form, or the csrf_token_id option (see the Form documentation).
Configuration
config/framework/csrf.yaml (optional, key framework.csrf):
field_name: _token
header_name: X-CSRF-TOKEN
session_key: _csrf
| Option | Default | Description |
|---|---|---|
field_name |
_token |
name of the form field |
header_name |
X-CSRF-TOKEN |
name of the HTTP header |
session_key |
_csrf |
session key holding the tokens |
PHP API
NeoPHP\Component\Csrf\Contract\CsrfInterface (implemented by CsrfManager):
| Method | Description |
|---|---|
getToken(string $id): string |
masked token (created when missing) |
refreshToken(string $id): string |
replaces the token and returns it |
removeToken(string $id): void |
removes the token |
hasToken(string $id): bool |
whether a token exists for the id |
isTokenValid(string $id, ?string $token): bool |
checks a submitted token |
getFieldName(): string |
configured field name |
getHeaderName(): string |
configured header name |
new CsrfManager(SessionInterface $session, array $options = []) builds a standalone instance.
Exceptions
| Exception | Description |
|---|---|
NeoPHP\Component\Csrf\Exception\CsrfException |
base exception of the component |
NeoPHP\Component\Csrf\Exception\InvalidCsrfTokenException |
missing or invalid token with #[Csrf], HTTP 403 |
Changelog
- v1.12.0 — Csrf component: tokens in the session, automatic token in forms,
csrf_token()/csrf_field()helpers,getCsrfToken()/isCsrfTokenValid()in controllers,#[Csrf]attribute.