nerdost / frontend-2fa
Email-based two-factor authentication for TYPO3 frontend users
Package info
gitlab.com/nerdost-gmbh/typo3-frontend-mail-2fa
Type:typo3-cms-extension
pkg:composer/nerdost/frontend-2fa
Requires
- php: ^8.2 || ^8.3 || ^8.4
- typo3/cms-core: ^14.3
Requires (Dev)
- phpunit/phpunit: ^11.5
- typo3/testing-framework: ^9.0
Suggests
- evoweb/extender: Required only for the automatic evoweb/sf-register model integration
- evoweb/sf-register: Adds the 2FA checkbox to frontend registration and profile forms
- in2code/femanager: Can expose the 2FA field in frontend user forms
Provides
None
Conflicts
None
Replaces
None
This package is not auto-updated.
Last update: 2026-09-23 10:31:28 UTC
README
Email-based two-factor authentication for TYPO3 frontend users. After entering their password, users confirm their login with a six-digit code sent by email. The code is entered directly in the existing felogin form.
2FA can be enabled per frontend user or frontend user group, including nested groups.
| Code entry | Security email |
|---|---|
Maintained by Nerdost GmbH.
Installation
Requirements: TYPO3 14.3 or newer (14.x), PHP 8.2–8.4, an existing felogin setup and configured outgoing mail.
Install the extension and apply the database schema update:
composer require nerdost/frontend-2fa
Add its site set to your site package. Include typo3/felogin if your site does not already provide it:
# EXT:site_package/Configuration/Sets/Site/config.yaml
name: vendor/site
label: Website
dependencies:
- typo3/felogin
- nerdost/frontend-2fa
Keep the login form available during verification. The extension replaces the content inside the rendered felogin form. Do not hide the login content element for authenticated users or move it into a layout that disappears after password authentication. The form must submit to a TYPO3 frontend page; AJAX and headless login flows are not supported by the bundled integration.
Test the full login flow on your site's login page before enabling 2FA for an entire group.
Enable 2FA
In the TYPO3 backend, open a Frontend User or Frontend User Group and enable the email 2FA checkbox under Security. A user must complete 2FA if it is enabled on their own record or on any of their direct or nested groups.
A valid email address is required. Users with an invalid fe_users.email are not challenged, even when their group requires 2FA. Saving a user with an invalid email address through the backend DataHandler also clears their individual 2FA flag. Check all group members' email addresses before applying a group-wide requirement.
To offer the individual setting in frontend registration or profile forms, see Optional frontend integrations.
Login flow
After TYPO3 validates the password, Frontend 2FA sends the code and displays the verification form, with options to resend the code or cancel. The recipient address is masked in the form. Emails are sent as HTML and plain text, using the current site language (German and English translations are included).
By default, a code is valid for 10 minutes, with five incorrect attempts allowed. Another code can be requested after 60 seconds, up to three additional times. Resending invalidates the previous code and renews the validity period, but does not reset the attempt counter. Expiry, too many incorrect attempts, cancellation, an invalid request token or a mail failure ends the login; the user must sign in again.
On success, the extension marks the session as verified, rotates the session ID and redirects to the login return URL. A redirect_url is accepted only if it is root-relative or has the same scheme, host and port as the request; otherwise, the current request URL is used.
If 2FA is enabled for a user who is already logged in, their existing session is not automatically marked as verified and may be challenged on the next request. The sf-register Edit integration explicitly preserves the user's current session when they enable 2FA in their own profile.
Site settings
The nerdost/frontend-2fa site set provides these settings:
| Setting | Default | Allowed range |
|---|---|---|
frontend2fa.challenge.lifetime | 600 s | 60–3600 s |
frontend2fa.challenge.maxAttempts | 5 | 1–20 |
frontend2fa.challenge.resendCooldown | 60 s | 10–600 s |
frontend2fa.challenge.maxResends | 3 | 0–10 |
Set maxResends to 0 to disable resending. Values outside the permitted range are clamped; non-integer values use the default.
Templates and localization
| Setting | Default |
|---|---|
frontend2fa.view.templateRootPath | EXT:frontend_2fa/Resources/Private/Templates/ |
frontend2fa.view.partialRootPath | EXT:frontend_2fa/Resources/Private/Partials/ |
frontend2fa.view.layoutRootPath | EXT:frontend_2fa/Resources/Private/Layouts/ |
frontend2fa.email.templateRootPath | EXT:frontend_2fa/Resources/Private/Templates/Email/ |
Code form: Copy Resources/Private/Templates/Challenge.fluid.html to your site package and set frontend2fa.view.templateRootPath to the containing directory. The existing felogin form supplies the <form> element; do not create a nested form. Keep the request-token field and the input names frontend_2fa[code] and frontend_2fa[action]. The default markup uses frontend-2fa classes alongside some Bootstrap-compatible classes.
Email: Override OneTimeCode.fluid.html and OneTimeCode.fluid.txt in the configured email template directory. Both receive {code} and {lifetimeMinutes}. Translations are in Resources/Private/Language/locallang.xlf and de.locallang.xlf.
Optional frontend integrations
Neither integration is needed for login. Both expose the individual fe_users.tx_frontend2fa_enabled setting; disabling this checkbox does not override a requirement set on a group.
sf-register
Install sf-register and Extender:
composer require evoweb/sf-register evoweb/extender
When both are present, the 2FA checkbox is added after the email field in the Create and Edit field selections. The bundled form and preview partials can be overridden through your sf-register partial paths.
When a user enables 2FA in their own profile through sf-register Edit, their current session stays valid; the code is required at the next login.
femanager
With femanager installed, select Enable two-factor authentication by email in the New and/or Edit plugin's field options. The extension supplies the user-model mapping and field partial. Extender is not needed for femanager.
Troubleshooting
Code form is missing or login returns HTTP 500. Ensure the page still renders a regular felogin form with logintype=login while verification is pending. Check for redirects, hidden login elements and modified form markup. The log message is Frontend 2FA challenge could not replace a felogin form.
No code email arrives. Check fe_users.email, TYPO3's mail transport and sender configuration. Search the log for Frontend 2FA email could not be sent or Frontend 2FA email could not be resent. A mail failure terminates the login.
A group member is not challenged. Check their email address, the user and group flags, and nested group assignments. An invalid email address exempts the user from enforcement.
Resend is unavailable. The cooldown or resend limit may have been reached. Resends do not restore incorrect attempts; once the challenge ends, a fresh password login is required.
Custom AJAX, JSON and headless login implementations need a dedicated integration; overriding the Fluid template is not sufficient.
For developers
FrontendMfaMiddleware runs after frontend authentication and request-token handling, before the page resolver. It checks the authenticated user against EffectiveTwoFactorPolicy, which evaluates the user flag, direct and nested group flags, and email validity.
ChallengeManager generates a random six-digit code and challenge ID. The frontend session stores an HMAC-SHA256 of the ID and code, expiration and attempt/resend counters, the masked recipient and the return URL. The HMAC uses TYPO3's SYS.encryptionKey; only OneTimeCodeMailer receives the plaintext code for delivery. No additional database table is required.
While verification is pending, the middleware renders the page with an anonymous frontend-user and group context, then replaces the first matching felogin form's contents with the Fluid challenge. It preserves the enclosing <form> and matches an input with name="logintype" and value="login". The verify, resend and cancel actions require a scoped, single-use TYPO3 request token (frontend-2fa/challenge). On success, the middleware stores frontend_2fa_verified and returns a 303 redirect. Challenge responses set Cache-Control: no-store, private and X-Robots-Tag: noindex, nofollow.
The main integration points are Configuration/RequestMiddlewares.php (middleware), Configuration/TCA/Overrides/ and ext_tables.sql (activation fields), FrontendUserDataHandlerHook (backend email validation), and Configuration/Services.php (optional frontend integrations).
Security considerations
Attempt and resend limits are scoped to the frontend session, not to an IP address or all sessions of a user. Add abuse protection if your application requires stronger rate limiting. Email-based 2FA depends on access to the user's mailbox and is not phishing-resistant.
License
Copyright Nerdost GmbH. Licensed under GPL-2.0-or-later.