Changelog
Version 1.0.1
Login fixes, and the end-to-end suite in CI
Security
- The login options endpoint no longer tells a caller which usernames exist. A username-first request for a known account was answered with assertion options and status 200, one for an unknown account with 401 and an error body, so the frontend users of a site could be enumerated one request at a time. Unknown accounts and accounts without a passkey on the site are now answered with decoy options: same status, same keys, and credential descriptors derived from the username with HMAC-SHA256 under the encryption key, so they are stable per username and cannot be told apart from real ones. The ceremony then fails in the browser the way a cancelled one does.
- All username-first answers take the same time. The random delay that used to sit in the unknown-account branch ran on that side only, which made the response time a second way to tell the answers apart. Every username-first answer now leaves after a shared floor of 150 ms. Work that runs past that floor still shows its own duration; such a request logs a warning with the overrun.
Bugfixes
- A passkey login on a page without felogin now establishes a session.
After a successful ceremony the script posted the login token through a
form it assembled itself, and TYPO3 refuses a frontend login whose
__RequestTokenis missing or carries the wrong scope — silently, with a 200 and no session cookie. The login plugin template now renders a hidden form whose token has the scopecore/user-auth/fe, and the script only submits forms TYPO3 rendered. - The backend module renders on TYPO3 13. The dashboard and help
templates passed the
stateoff:be.infoboxas a string; TYPO3 13 types that argumentintand answered every module page with 503.
Tests
- The end-to-end suite runs. 15 Playwright tests drive registration,
discoverable login through to an authenticated session, credential
management, enrollment, recovery and the backend module against a TYPO3
instance the shared test runner provisions, and
.github/workflows/e2e.ymlruns them on TYPO3 13 and 14 for every pull request. Before this release every specification was skipped and no workflow ran them.
Version 1.0.0
Stable, and paired with nr_passkeys_be 1.0
Breaking / Important
- The extension state changes from ``beta`` to ``stable``. From this release on the public API follows semantic versioning: a removal or an incompatible change to a public class, method or configuration setting needs a new major version.
- ``nr_passkeys_be`` 1.0.0 or newer is required. That release removed
RateLimiterService::checkRateLimit()and::recordAttempt(), which this extension called inLoginControllerandRecoveryController. Both call sites now useconsumeRateLimit(), which performs the check and the increment inside one critical section — the separate check-then- record pair left a window in which concurrent requests could all pass the check before any of them incremented. No installation could reach the broken combination: the dependency constraint refusednr_passkeys_be1.0.0 until this release.
Bugfixes
- Passkey login works on SQLite-backed installations.
tx_nrpasskeysfe_credential.credential_idis avarbinarycolumn, but the lookups bound it as a plain string andsave()declared no column types. MySQL compares that regardless; SQLite stores a string-bound parameter as a TEXT storage class, which never equals the BLOB the value was written as, so the credential could not be found and the login failed. The lookups now bind withParameterType::BINARYand the insert declarescredential_id,user_handleandpublic_key_coseby type.
Tests
- The functional suite passes on SQLite as well as MySQL: 113 tests on both,
where SQLite previously produced twelve failures. The end-to-end
specifications under
Tests/E2E/remain drafts and are not part of any suite that runs.
Version 0.6.0
Conditional UI and CType plugin registration
This release shipped without a changelog entry. Its contents:
Features
- WebAuthn Conditional UI on the login plugin -- the browser offers a stored passkey directly in the username field's autofill menu, so a returning user never has to press the passkey button. The plugin's discoverable switch governs it.
- Plugins register as CType on both supported TYPO3 versions, so the content elements appear in the element wizard on v13 and v14 alike.
- Rector runs with the shared organisation configuration, including the TYPO3 v13 level set.
Version 0.5.0
Unified passkey dashboard widgets
Breaking / Important
- Standalone dashboard widgets removed --
nr_passkeys_feno longer registers its ownPasskey adoptionandActive passkey credentialsdashboard widgets. When both extensions are installed the dashboard previously showed four near-identical widgets; it now shows the single unified widget set owned bynr_passkeys_be. - Frontend adoption is now a segment of the unified widgets --
Frontend statistics appear as the "Frontend users" segment (a second
doughnut ring and a summed credential count) of the
nr_passkeys_bewidgets, contributed via the newnr_passkeys_be.adoption_stats_providerservice tag (FrontendPasskeyAdoptionStatsProvider). Backend and frontend user populations are shown separately, never summed. - Requires
netresearch/nr-passkeys-be^0.12 -- the extension point (PasskeyAdoptionStatsProviderInterfaceand thePasskeyAudienceStatsDTO) is provided fromnr_passkeys_be0.12.0. The Composer constraint and theext_emconf.phpdependency were tightened accordingly. - TYPO3 v13 compatibility shim removed --
nr_passkeys_feno longer references anytypo3/cms-dashboardsymbol, so theAdminOnlyWidgetInterfacecompat shim (and itsautoload.filesentry) has been dropped.
Version 0.1.0
Initial release
This is the first public release of Passkeys Frontend Authentication
(nr_passkeys_fe). It provides passkey-first login for TYPO3
frontend users with all core features.
Features
- Passkey-first login -- Discoverable (usernameless) and username-first login flows via the NrPasskeysFe:Login plugin. Supports all FIDO2/WebAuthn-compliant authenticators.
- felogin integration -- Injects a passkey button into the standard felogin plugin via PSR-14 event listener. No login provider switching required.
- Self-service management -- Frontend users can enroll, rename, and revoke their own passkeys via the NrPasskeysFe:Management plugin.
- Recovery codes -- Users can generate 10 one-time recovery codes (bcrypt hashed) as a fallback when no authenticator device is available.
- Per-site RP ID -- Each TYPO3 site has an independent WebAuthn
Relying Party configuration via
config.yaml. - Per-group enforcement -- Four enforcement levels (Off, Encourage, Required, Enforced) configurable per site and per frontend user group with configurable grace periods.
- Post-login interstitial -- Users without a passkey are shown an enrollment interstitial when enforcement level is Required or Enforced.
- Backend admin module -- Administrators can view adoption statistics, manage credentials, and configure enforcement from Admin Tools > Passkey Management FE.
- PSR-14 events -- Seven events for extensibility: before/after authentication, before/after enrollment, enforcement level resolved, passkey removed, recovery codes generated.
- Security hardened -- HMAC-signed challenges, nonce replay
protection, per-IP rate limiting, and account lockout (shared with
nr-passkeys-be). - Vanilla JavaScript -- Zero runtime npm dependencies. The frontend JavaScript uses only the native WebAuthn browser API.
Requirements
- TYPO3 13.4 LTS or 14.1+
- PHP 8.2+
netresearch/nr-passkeys-be^0.6- HTTPS
Known limitations
- Magic link login is deferred to v0.2 (ADR-011). The event class and service will be added in v0.2.
- No admin-initiated passkey registration on behalf of users.