---
title: "Feature: #109365 - Introduce module access gates for backend modules"
manual: "TYPO3 Core Changelog"
version: "main"
permalink: "https://docs.typo3.org/permalink/changelog:feature-109365-1774538611"
source: "Changelog/14.2/Feature-109365-IntroduceModuleAccessGatesForBackendModules.rst"
typo3-version: "14.2"
typo3-major: 14
type: "feature"
issue: 109365
forge: "https://forge.typo3.org/issues/109365"
tags: ["Backend", "PHP-API", "ext:backend"]
rendered: "2026-09-20T18:31:11+00:00"
---

# Feature: #109365 - Introduce module access gates for backend modules {#feature-109365-1774538611}

See [forge#109365](https://forge.typo3.org/issues/109365)

## Description {#description}

The previously hard-coded module access checks (`user`, `admin`,
`systemMaintainer`) in the backend module registration have been replaced
with an extensible gate system. Each access type is now handled by a dedicated
gate class which implements
`ModuleAccessGateInterface`.

TYPO3 ships three built-in gates that preserve existing behavior:

-   `UserGate` \- grants access
    to admin users and users/groups with explicit module permissions
    (`be_users.userMods` / `be_groups.groupMods`)
-   `AdminGate` \- grants access
    only to admin users
-   `SystemMaintainerGate` \-
    grants access only to system maintainers

Extension authors can register custom gates using the
`#[AsModuleAccessGate]` PHP attribute. A gate receives the module and the
current backend user and returns one of three results:

-   `ModuleAccessResult::Granted` \- access is explicitly allowed
-   `ModuleAccessResult::Denied` \- access is explicitly denied
-   `ModuleAccessResult::Abstain` \- the gate cannot decide (not responsible
    for this access type)

### Example: Custom module access gate {#example-custom-module-access-gate}

**EXT:my_extension/Classes/Module/AccessGate/EditorGate.php**

```php
namespace MyVendor\MyExtension\Module\AccessGate;

use TYPO3\CMS\Backend\Module\ModuleAccessGateInterface;
use TYPO3\CMS\Backend\Module\ModuleAccessResult;
use TYPO3\CMS\Backend\Module\ModuleInterface;
use TYPO3\CMS\Core\Attribute\AsModuleAccessGate;
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;

#[AsModuleAccessGate(identifier: 'myEditor')]
final readonly class EditorGate implements ModuleAccessGateInterface
{
    public function decide(
        ModuleInterface $module,
        BackendUserAuthentication $user,
    ): ModuleAccessResult {
        if ($module->getAccess() !== 'myEditor') {
            return ModuleAccessResult::Abstain;
        }
        // Custom logic: Check for a specific user group.
        return in_array(3, $user->userGroupsUID, true)
            ? ModuleAccessResult::Granted
            : ModuleAccessResult::Denied;
    }
}
```

The custom gate can then be referenced in the module registration:

**EXT:my_extension/Configuration/Backend/Modules.php**

```php
return [
    'my_module' => [
        'access' => 'myEditor',
        'labels' => 'my_extension.module',
        // ...
    ],
];
```

### Ordering gates {#ordering-gates}

Gates support `before` and `after` parameters to set their
evaluation order when multiple gates are registered:

```php
#[AsModuleAccessGate(identifier: 'myEditor', after: ['user'])]
final readonly class EditorGate implements ModuleAccessGateInterface
{
    // ...
}
```

## Impact {#impact}

Extension authors can now define custom module access strategies beyond the
built-in `user`, `admin`, and `systemMaintainer` levels by implementing
`ModuleAccessGateInterface` and
registering it with the `#[AsModuleAccessGate]` attribute.

Existing module registrations using the built-in access values continue to
work without changes.
