Deployment Scenarios
Passkeys are bound to a specific domain (the Relying Party ID). This chapter explains how to configure the extension across different environments and how to handle common deployment patterns.
On this page
Single environment
The simplest setup: one TYPO3 instance with one domain.
Leave rpId and origin empty (the default). The extension auto-detects both values from the incoming HTTP request. Each passkey is registered against the domain it was created on.
This works for:
- A single production instance (e.g.
cms.example.com) - A local DDEV site (e.g.
mysite.ddev.site)
No additional configuration is needed.
Multi-environment (local / staging / production)
A typical setup has three environments:
- Local development:
mysite.ddev.site(ormysite.local) - Staging:
staging.example.com - Production:
www.example.com
Recommended: separate passkeys per environment
Leave rpId empty on all environments. Each environment auto-detects its own domain, so passkeys are environment-specific. Users register a separate passkey on each environment they need access to.
Modern authenticators (iCloud Keychain, Windows Hello, 1Password, YubiKey) make registering on multiple environments trivial -- it takes about 10 seconds per environment.
Tip
This is the recommended approach. It avoids sharing secrets across environments and keeps each environment fully independent.
Environment-specific configuration
Use TYPO3_CONTEXT to apply different settings per environment:
// Production and Staging: enforce passkey-only login
if (str_starts_with((string)getenv('TYPO3_CONTEXT'), 'Production')) {
$GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['nr_passkeys_be']['disablePasswordLogin'] = '1';
}
// Development: keep password login available for convenience
// (disablePasswordLogin defaults to '0', no override needed)
Because enforcement is per user (only users with registered passkeys are affected), enabling disablePasswordLogin on production is safe even if not all users have passkeys yet -- they can still log in with a password. Keeping the setting disabled on development means all users (including those with passkeys) can use password login for convenience.
Tip
Consider enabling on staging first to verify the workflow, and communicate the change to backend users who already have passkeys -- they will no longer be able to fall back to password login.
Database synchronisation
When syncing the production database to staging or local (a common workflow), the passkey credential table will contain credentials bound to the production domain. These credentials will not work on a different domain.
Exclude the credential table from database syncs:
mysqldump --ignore-table=mydb.tx_nrpasskeysbe_credential mydb > dump.sql
ignore_tables:
- tx_nrpasskeysbe_credential
After importing a production database dump, users simply register fresh passkeys on the local or staging environment. Because enforcement is per user, users with no credentials in the table can log in with a password regardless of the disablePasswordLogin setting.
Important
Exclude the credential table from syncs when disablePasswordLogin is enabled. The per-user enforcement counts all non-deleted, non-revoked credentials regardless of which domain they were registered on (see ADR-0002). If production credentials are imported into a different environment, users appear to have passkeys (blocking password login) even though those passkeys do not work on the new domain.
Note
You do not need to exclude be_users or any other table. Only
tx_nrpasskeysbe_credential is domain-specific. No security data
is exposed by an accidental sync because the public keys are useless
without the private keys stored on users' authenticators.
User onboarding
Onboarding workflow with disablePasswordLogin
When disablePasswordLogin is enabled, the extension enforces passkey-only login per user: password login is blocked only for users who have at least one registered passkey. Users without passkeys can still log in with a password.
This enables a smooth onboarding workflow:
- Admin creates a new backend user with a password (as usual in TYPO3).
- User logs in with their password for the first time.
- User registers a passkey in User Settings > Passkeys.
- From this point on, the user must use their passkey -- password login is no longer accepted for this account.
Note
An admin cannot register a passkey on behalf of another user. The WebAuthn ceremony requires physical interaction with the user's own authenticator (TouchID, YubiKey, etc.).
Recovery scenarios
If a user loses access to their authenticator:
- An admin revokes the user's passkeys via the Admin API. Each revocation is recorded with the admin's UID and timestamp for audit purposes.
- Once all passkeys are revoked, password login becomes available again for that user (the per-user enforcement lifts when no active credentials remain).
- The user logs in with their password and registers a new passkey.
Tip
Consider requiring users to register at least two passkeys on different authenticators (e.g. laptop + phone) for redundancy.
Containerized and multi-server deployments
When running TYPO3 in Docker containers or behind a load balancer, the file-based cache backends lose state on container restart and are not shared across servers. This affects nonce replay protection and rate limiting.
See Multi-server cache backends for Redis configuration, and Reverse proxy and IP detection for rate limiting behind a load balancer.
Local development with DDEV
DDEV sites (*.ddev.site) use HTTPS by default and are treated as
secure contexts by browsers. Passkeys work out of the box.
ddev start
# Open https://mysite.ddev.site/typo3 -- passkeys work immediately
For http://localhost (without HTTPS), most browsers also treat this
as a secure context, so passkeys will work. However, custom local
domains over plain HTTP (e.g. http://mysite.local) will not
work -- WebAuthn requires a secure context.
See also Troubleshooting: HTTPS requirement.
See also
Security: Production deployment requirements for trusted hosts pattern, reverse proxy configuration, and multi-server cache backends.