---
title: "Form protection tool"
manual: "TYPO3 Explained"
version: "main"
permalink: "https://docs.typo3.org/permalink/t3coreapi:csrf-backend@main"
source: "ApiOverview/FormProtection/Index.rst"
modified: "2026-09-16T13:05:25+00:00"
---

# Form protection tool

The TYPO3 Core provides a generic way of protecting forms against cross-site
request forgery (CSRF).

> [!WARNING]
> **Attention**
>
> This **requires a logged-in user** whether in frontend or backend. CSRF
> protection is not supported for anonymous users. Without a logged-in user
> the token will always be `dummyToken`. See `77403` for details.

For each form in the backend/frontend (or link that changes some data), create a
token and insert it as a hidden form element. The name of the form element does
not matter; you only need it to get the form token for verifying it.

## Examples

**EXT:my_extension/Classes/Controller/FormProtectionExample.php**

```php
<?php

declare(strict_types=1);

namespace MyVendor\MyExtension\Controller;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use TYPO3\CMS\Core\FormProtection\FormProtectionFactory;

final class FormProtectionExample
{
  public function __construct(
    private readonly FormProtectionFactory $formProtectionFactory,
  ) {}

  public function handleRequest(ServerRequestInterface $request): ResponseInterface
  {
    $formProtection = $this->formProtectionFactory->createFromRequest($request);

    $formToken = $formProtection->generateToken('BE user setup', 'edit');

    $content = '<input type="hidden" name="formToken" value="' . $formToken . '">';

    // ... some more logic ...
  }
}

```

The three parameters of the `generateToken()` method:

-   `$formName`
-   `$action` (optional)
-   `$formInstanceName` (optional)

can be arbitrary strings, but they should make the form token as specific as
possible. For different forms (for example, BE user setup and editing a
`tt_content` record) or different records (with different UIDs) from the
same table, those values should be different.

For editing a `tt_content` record, the call could look like this:

**EXT:my_extension/Classes/Controller/FormProtectionExample.php (Excerpt)**

```php
$formToken = $formProtection->generateToken('tt_content', 'edit', (string)$uid);
```

When processing the data that has been submitted by the form, you can check that
the form token is valid like this:

**EXT:my_extension/Classes/Controller/FormProtectionExample.php (Excerpt)**

```php
if ($dataHasBeenSubmitted &&
    $formProtection->validateToken(
        $request->getParsedBody()['formToken'] ?? '',
        'BE user setup',
        'edit'
    ) ) {
    // process the data
} else {
    // No need to do anything here, as the backend form protection will
    // create a flash message for an invalid token
}
```

As it is recommended to use `FormProtectionFactory->createForRequest()`
to auto-detect which type is needed, one can also create a specific type
directly:

**EXT:my_extension/Classes/Controller/FormProtectionExample.php (Excerpt)**

```php
// For backend
$formProtection = $this->formProtectionFactory->createFromType('backend');

// For frontend
$formProtection = $this->formProtectionFactory->createFromType('frontend');
```
