---
title: "Form protection tool"
manual: "TYPO3 Explained"
version: "11.5"
permalink: "https://docs.typo3.org/permalink/t3coreapi:csrf@11.5"
source: "ApiOverview/FormProtection/Index.rst"
rendered: "2026-10-21T15:30:00+00:00"
---

> [!WARNING]
> **Attention**
>
> TYPO3 v11 has reached end-of-life as of October 31th 2024 and
> is no longer being maintained. Use the version switcher on the top
> left of this page to select documentation for a supported version of TYPO3.
>
> Need more time before upgrading?
> You can purchase Extended Long Term Support (ELTS) for TYPO3 v11 here:
> [TYPO3 ELTS](https://typo3.com/services/extended-support-elts).

# Form protection tool {#csrf}

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.

-   [Usage in the backend](https://docs.typo3.org/permalink/t3coreapi:usage-in-the-backend@11.5)
-   [Usage in the frontend](https://docs.typo3.org/permalink/t3coreapi:usage-in-the-frontend@11.5)

## Usage in the backend {#csrf-backend}

For each form in the BE (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.

```php
// use TYPO3\CMS\Core\FormProtection\FormProtectionFactory;

$formToken = FormProtectionFactory::get()
    ->generateToken('BE user setup', 'edit');
$this->content .= '<input type="hidden" name="formToken" value="' . $formToken . '">';
```

The three parameters `$formName`, `$action` (optional) and
`$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:

```php
// use TYPO3\CMS\Core\FormProtection\FormProtectionFactory;

$formToken = FormProtectionFactory::get()
    ->generateToken('tt_content', 'edit', $uid);
```

Finally, you need to persist the tokens. This makes sure that
generated tokens get saved, and also that removed tokens stay removed:

```php
// use TYPO3\CMS\Core\FormProtection\FormProtectionFactory;

FormProtectionFactory::get()
    ->persistTokens();
```

In backend lists, it might be necessary to generate hundreds of tokens.
So, the tokens are not automatically persisted after creation for performance
reasons.

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

```php
// use TYPO3\CMS\Core\FormProtection\FormProtectionFactory;
// use TYPO3\CMS\Core\Utility\GeneralUtility;

if ($dataHasBeenSubmitted &&
    FormProtectionFactory::get()->validateToken(
        (string) GeneralUtility::_POST('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
}
```

> [!NOTE]
> The `validateToken()` method invalidates the token with the token ID.
> So calling the validation with the same parameters twice in a row will
> always return `false` for the second call.

> [!WARNING]
> **Attention**
>
> The tokens must be validated **before** the tokens are persisted. This
> makes sure that the tokens, that get invalidated by `validateToken()`
> cannot be used again.

## Usage in the frontend {#usage-in-the-frontend}

Usage is the same as in [backend context](https://docs.typo3.org/permalink/t3coreapi:csrf-backend@11.5):

```php
   // use TYPO3\CMS\Core\FormProtection\FormProtectionFactory;
   // use TYPO3\CMS\Core\Utility\GeneralUtility;

   $formToken = FormProtectionFactory::get()
       ->generateToken('news', 'edit', $uid);

if ($dataHasBeenSubmitted
	&& FormProtectionFactory::get()->validateToken(
		GeneralUtility::_POST('formToken'),
		'news',
		'edit',
		$uid
	)
) {
	// process the data
} else {
	// Create a flash message for the invalid token
       // or just discard this request
}
```

> [!NOTE]
> The `validateToken()` invalidates the token with the token ID. So,
> calling the validation with the same parameters twice in a row will always
> return `false` for the second call.

> [!WARNING]
> **Attention**
>
> The tokens must be validated **before** the tokens are persisted. This makes
> sure that the tokens that get invalidated by `validateToken()` cannot
> be used again.
