Skip to content

Add webAuthn 2FA to support Yubikeys as additional 2nd factors#47

Merged
JamesAlias merged 20 commits into
sandstorm:mainfrom
tobiasgruber:add-webauthn-2fa
Jun 19, 2026
Merged

Add webAuthn 2FA to support Yubikeys as additional 2nd factors#47
JamesAlias merged 20 commits into
sandstorm:mainfrom
tobiasgruber:add-webauthn-2fa

Conversation

@tobiasgruber

@tobiasgruber tobiasgruber commented May 30, 2026

Copy link
Copy Markdown
Contributor

Added WebAuthn / FIDO2 as a second option for Two Factor Authentication, so hardware security keys (e.g. Yubikeys) can be used as second factors alongside TOTP.

  • Claude Code helped me refactor the logic to support multiple second factor types. Users can register one TOTP token and one security key, and pick which to use at login.
  • The second factor login screen only shows the 2FA variants that exist for the account.
  • Tested locally with Yubikey 4 and 5.

Breaking changes

  • Dropped support for Neos 7 and PHP < 8.2. The package now requires php: ^8.2 and neos/neos: ^8.0 | ^9.0.
  • Added new dependency web-auth/webauthn-lib: ^4.9.3.
  • Pinned spomky-labs/otphp to ^11.5 to ensure a security-fixed version.

Migration (run after deployment)

Added migration Version20260519120000.php:

  • widens the secret column on sandstorm_neostwofactorauthentication_domain_model_secondfactor from VARCHAR(255) to TEXT, so it can hold the serialized WebAuthn credential data (which exceeds 255 chars). Without it, registering a security key will fail to persist.
  • run it with ./flow doctrine:migrate

Configuration

Added settings for WebAuthn configuration (relying party, user verification, timeout) — see Settings.yaml and the README for examples and authenticator compatibility notes.

Note: browsers expose WebAuthn only over https:// or on localhost, so the backend must be served over HTTPS in production for the security-key flow to work.

Attestation

By design, we do not implement attestation statement formats other than none. We always request the none conveyance preference, so the browser does not return identifying attestation data about the authenticator. When loading a credential, only the none and fido-u2f attestation statement formats are accepted (fido-u2f is required for U2F-only authenticators registered via the browser's U2F-compat fallback). Other attestation statement types are not supported. This keeps the implementation simpler and avoids collecting authenticator-identifying data we don't need for second-factor verification.

Tests

Added E2E tests (login and backend module) covering WebAuthn registration and login, including the case where both OTP and WebAuthn are set up and the WebAuthn challenge is restarted.

Screenshots

Register 2nd Factor Select Screen:
Register_2ndFactorSelect_Screen

Register Security Key Screen:
RegisterSecurityKey_Screen

List of registered 2nd Factors Screen:
ListOfRegistered2ndFactors_Screen

Second factor login Screen:
2FA_Login_Screen

@tobiasgruber tobiasgruber changed the title Add webauthn 2fa to support Yubikeys as additional 2nd factors Add webAuthn 2FA to support Yubikeys as additional 2nd factors May 30, 2026
@JamesAlias JamesAlias merged commit 1bca3b0 into sandstorm:main Jun 19, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants