enhancement
major
minor
defect
critical
major
minor
major
#30118
Passkeys per application can be used either for password-less login or as a second factor, but not both at the same time
Context
In #30074, a user logs in to the React interface using a passkey—either password-free or as a second factor after entering a password. Every passkey created was valid for both purposes: It was discoverable and could be used to log in on its own, and because the account had “set up” a second factor with it, logging in with a password subsequently required the same passkey. Anyone who can log in with the passkey alone has no reason to enter a username and password first.
Behavior
The application defines the purpose of passkeys (the “usage” option of the PasskeyService) and offers only the corresponding setup options:
- login (default) – Log in without a password: The login form offers “Log in with Passkey.” Passkeys are created to be discoverable and always require user verification (PIN/biometrics). In Settings → Security, a separate section titled “Log in with Passkey (after password)” manages the passkeys. A passkey is not a second factor: After logging in with a password, no passkey is required, and an account with the “required” setting but no second factor sets up the Authenticator app. Logging in with a passkey fulfills the MfaRequirement “required.” Even an account with “disabled” can create passkeys: Here, the passkey is a login method just like the password.
- second-factor - Passkey as a second factor: The login form does not offer passkey login (the button is hidden). Passkeys are created in a hidden location. The “Passkeys” section is located in the “Two-Factor Authentication” section next to the Authenticator app; an account with “Passkey” confirms the login after entering the password using a passkey, while an account with “required” but no second factor can set up a passkey during login. An account with “disabled” does not create passkeys.
- The service rejects any authentication method that does not match the setting (passwordless login for “second-factor,” passkey after the password for “login”), regardless of what the user interface offers.
- Stored passkeys are retained when the setting is changed. A passkey created as a second factor (not searchable) will not allow login without a password after switching to “login”; the user must then create a new one.
Technical Implementation
- PasskeyService.Config#getUsage() (usage, enumeration PasskeyUsage : login / second-factor, default: login) determines the residentKey and user verification for registration (PendingRegistration#requiresUserVerification), which logins are accepted by startAuthentication (ERROR_NO_PASSWORDLESS_LOGIN, ERROR_NO_SECOND_FACTOR) and mayUsePasskeys.
- PasskeySecondFactor is only configured or configurable for “second-factor”; this triggers the status bar, selection of the authentication method, and the “last-factor” rule from <delete-passkey/>.
- <if-passkey-usage usage="…"> (PasskeyUsageElement) displays its content only for the specified use case and otherwise takes up no space; the settings overlays thus place the shared passkey list (passkey-list.view.xml). The views do not read the configuration via TL-Script (appConfig is reserved for administrators).
- <passkey-login> is hidden if the usage scenario does not permit its type of login.
- Fixed: TLWebAuthn (com.top_logic.layout.react) did not respect the hidden flag when rendered as a child of another control (e.g., in the login form); a hidden button now renders nothing and does not trigger any authentication process.
- No new model attribute, no data migration. Documentation: authentication/passkeys, authentication/mfa.
Verification
Tests: TestPasskeyService, TestPasskeyCeremony, TestPasskeyUsageElement, TestDeletePasskeyAction, TestPasskeyFunctions, TLWebAuthn.test.tsx. Tested in tl-demo-react using Chrome’s virtual authenticator in both use cases: Button in the sign-in form, placement in settings, creation (findable or unfindable), passwordless sign-in or passkey after entering a password, sign-in with a password without a passkey prompt upon login, deletion.