diff --git a/apps/login/cypress/integration/login.cy.ts b/apps/login/cypress/integration/login.cy.ts index d4edf570d68..1d6472d5e66 100644 --- a/apps/login/cypress/integration/login.cy.ts +++ b/apps/login/cypress/integration/login.cy.ts @@ -156,12 +156,9 @@ describe("login", () => { }, }); }); - it("should redirect a user with passwordless authentication to /passkey/login", () => { + it("should redirect a user with passwordless authentication to /passkey", () => { cy.visit("/loginname?loginName=john%40zitadel.com&submit=true"); - cy.location("pathname", { timeout: 10_000 }).should( - "eq", - "/passkey/login", - ); + cy.location("pathname", { timeout: 10_000 }).should("eq", "/passkey"); }); }); }); diff --git a/apps/login/readme.md b/apps/login/readme.md index 15386cb2665..a085df7ea37 100644 --- a/apps/login/readme.md +++ b/apps/login/readme.md @@ -68,7 +68,7 @@ After a loginname is entered, a `listUsers` request is made using the loginName **USER FOUND:** If only one user is found, we query `listAuthenticationMethodTypes` to identify future steps. If no authentication methods are found, we render an error stating: _User has no available authentication methods._ (exception see below.) -Now if only one method is found, we continue with the corresponding step (/password, /passkey/login). +Now if only one method is found, we continue with the corresponding step (/password, /passkey). If multiple methods are set, we prefer passkeys over any other method, so we redirect to /passkey, second option is IDP, and third is password. If password is the next step, we check `loginSettings.passkeysType` for PasskeysType.ALLOWED, and prompt the user to setup passkeys afterwards. @@ -123,3 +123,33 @@ If `email` or `sms` is requested as method, the current session of the user is u The `time-based` (TOTP) method does not require a trigger, therefore no `updateSession()` is performed and no resendLink under the code field is shown. The submission of the code updates the session and continues to sign in the user. + +### /u2f + +/u2f + +This page requests a webAuthN challenge for the user and updates the session afterwards. + +Requests to the APIs made: + +- `getBrandingSettings(org?)` +- `getSession()` +- `updateSession()` + +When updating the session for the webAuthN challenge, we set `userVerificationRequirement` to `UserVerificationRequirement.DISCOURAGED` as this will request the webAuthN method as second factor and not as primary method. +After updating the session, the user is signed in. + +### /passkey + +/passkey + +This page requests a webAuthN challenge for the user and updates the session afterwards. + +Requests to the APIs made: + +- `getBrandingSettings(org?)` +- `getSession()` +- `updateSession()` + +When updating the session for the webAuthN challenge, we set `userVerificationRequirement` to `UserVerificationRequirement.REQUIRED` as this will request the webAuthN method as primary method to login. +After updating the session, the user is signed in. diff --git a/apps/login/src/app/(login)/passkey/login/page.tsx b/apps/login/src/app/(login)/passkey/page.tsx similarity index 100% rename from apps/login/src/app/(login)/passkey/login/page.tsx rename to apps/login/src/app/(login)/passkey/page.tsx diff --git a/apps/login/src/lib/server/loginname.ts b/apps/login/src/lib/server/loginname.ts index a566b30ad84..66fd2d824a6 100644 --- a/apps/login/src/lib/server/loginname.ts +++ b/apps/login/src/lib/server/loginname.ts @@ -123,9 +123,7 @@ export async function sendLoginname(command: SendLoginnameCommand) { command.organization ?? session.factors?.user?.organizationId; } - return redirect( - "/passkey/login?" + new URLSearchParams(paramsPasskey), - ); + return redirect("/passkey?" + new URLSearchParams(paramsPasskey)); } } else { // prefer passkey in favor of other methods @@ -144,7 +142,7 @@ export async function sendLoginname(command: SendLoginnameCommand) { command.organization ?? session.factors?.user?.organizationId; } - return redirect("/passkey/login?" + new URLSearchParams(passkeyParams)); + return redirect("/passkey?" + new URLSearchParams(passkeyParams)); } else if ( methods.authMethodTypes.includes(AuthenticationMethodType.IDP) ) { diff --git a/apps/login/src/ui/RegisterPasskey.tsx b/apps/login/src/ui/RegisterPasskey.tsx index 2b5c1b12e45..9391e62f63e 100644 --- a/apps/login/src/ui/RegisterPasskey.tsx +++ b/apps/login/src/ui/RegisterPasskey.tsx @@ -151,7 +151,7 @@ export default function RegisterPasskey({ // params.set("altPassword", ${false}); // without setting altPassword this does not allow password // params.set("loginName", resp.loginName); - router.push("/passkey/login?" + params); + router.push("/passkey?" + params); } else { router.push("/accounts?" + params); }