Feature: #109080 - Unified RateLimiterFactory with admin overrides
See forge#109080
Description
TYPO3's
\TYPO3\ has been
refactored to serve as the single entry point for all rate limiting across the
system. A new
\TYPO3\
extends Symfony's
Rate with additional convenience
methods for request-based and login rate limiting.
Previously, the backend and frontend password recovery features, as well as the Extbase rate limiting, each created Symfony rate limiter factories directly, bypassing TYPO3's factory. All consumers now use the central TYPO3 factory, which enables a unified admin override mechanism.
Extension developers should type-hint against
\TYPO3\ when injecting
the factory.
Admin overrides via TYPO3_CONF_VARS
A new configuration option
$GLOBALS
allows administrators to override any rate limiter's settings by its ID. Each key
is a limiter ID, and each value is an array of settings to override:
$GLOBALS['TYPO3_CONF_VARS']['SYS']['rateLimiter']['login-be'] = [
'limit' => 3,
'interval' => '5 minutes',
];
$GLOBALS['TYPO3_CONF_VARS']['SYS']['rateLimiter']['backend-password-recovery'] = [
'limit' => 1,
'interval' => '1 hour',
];
Known limiter IDs:
login-— Backend loginbe login-— Frontend loginfe backend-— Backend password resetpassword- recovery felogin-— Frontend password recoverypassword- recovery extbase-<class— ExtbaseSlug>-<action Method> #actions[Rate Limit]
Example limiter ID for Extbase action
The limiter ID for an Extbase action which uses the
#
attribute is constructed using the "slugified" classname and the
action method name.
namespace Vendor\MyExtension\Controller;
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
use TYPO3\CMS\Extbase\Attribute\RateLimit;
class MyController extends ActionController
{
#[RateLimit(limit: 5, interval: '10 minutes', message: 'ratelimit.dosomething')]
public function doSomethingAction(): ResponseInterface
{
return $this->redirect('index');
}
}
The limiter ID for the action is:
extbase-
General-purpose rate limiting
Extension developers can now use the factory for custom rate limiting needs.
The
create method is the recommended entry point for
request-scoped rate limiting. It automatically extracts the client's remote IP
from the PSR-7 request and uses it as the limiter key:
use Psr\Http\Message\ServerRequestInterface;
use TYPO3\CMS\Core\RateLimiter\RateLimiterFactoryInterface;
class MyService
{
public function __construct(
private readonly RateLimiterFactoryInterface $rateLimiterFactory,
) {}
public function doSomething(ServerRequestInterface $request): void
{
$limiter = $this->rateLimiterFactory->createRequestBasedLimiter(
$request,
[
'id' => 'my-extension-action',
'policy' => 'sliding_window',
'limit' => 10,
'interval' => '1 hour',
]
);
$limit = $limiter->consume();
if (!$limit->isAccepted()) {
// handle rate limit exceeded
}
}
}
For cases where a custom key is needed (e.g. a user ID instead of the IP), the
create method accepts an explicit configuration array and key:
$limiter = $this->rateLimiterFactory->createLimiter(
[
'id' => 'my-extension-action',
'policy' => 'sliding_window',
'limit' => 10,
'interval' => '1 hour',
],
$userId
);
Pre-configured named services can also be defined in Services.,
which are then injectable with the
create method from the
Rate:
myRateLimiter:
class: TYPO3\CMS\Core\RateLimiter\RateLimiterFactory
arguments:
$config:
id: 'my-custom-limiter'
policy: 'sliding_window'
limit: 5
interval: '10 minutes'
Impact
All rate limiting in TYPO3 now flows through a single factory that supports
admin-level overrides. Administrators can tune or restrict rate limits for any
component — login, password recovery, Extbase actions, or custom extensions —
without modifying code, using
$GLOBALS.
The login rate limiter now uses human-readable IDs (
login-,
login-) instead of SHA1 hashes. Existing cached rate limit state
from previous versions will expire naturally.