fix(login): Return promise from passkey authentication to fix automatic prompt (#10991)

# Which Problems Are Solved

The passkey login page was not rendering properly in production (Cloud
Run) deployments, with the submit button and component content not
appearing. Additionally, the automatic passkey prompt was not triggering
correctly.

# How the Problems Are Solved

Added the missing return statement before navigator.credentials.get() in
the submitLoginAndContinue function. This ensures the promise is
properly returned and chained in the useEffect hook, fixing the
automatic passkey prompt flow.

Removes the recently introduces guides to passkeys that could result in
a hydration error due to the <a> tag being rendered differently on
server / client environement

# Additional Changes

This issue was most probably introduced in PR #10971. The component uses
promise chaining (.then().catch().finally()) which requires the promise
to be returned, unlike the RegisterPasskey component which uses
async/await and works correctly without an explicit return.
This commit is contained in:
Max Peintner
2025-10-28 13:35:47 +01:00
committed by GitHub
parent 32500e3b0c
commit fa524e3b05
9 changed files with 7 additions and 45 deletions

View File

@@ -261,10 +261,6 @@
"verify": {
"title": "Mit einem Passkey authentifizieren",
"description": "Ihr Gerät wird nach Ihrem Fingerabdruck, Gesicht oder Bildschirmsperre fragen",
"info": {
"description": "Verwenden Sie den von Ihnen eingerichteten Passkey, um sich sicher zu authentifizieren. ",
"link": "Mehr über Passkeys erfahren"
},
"usePassword": "Passwort verwenden",
"submit": "Weiter",
"errors": {

View File

@@ -261,10 +261,6 @@
"verify": {
"title": "Authenticate with a passkey",
"description": "Your device will ask for your fingerprint, face, or screen lock",
"info": {
"description": "Use the passkey you set up to authenticate securely. ",
"link": "Learn more about Passkeys"
},
"usePassword": "Use password",
"submit": "Continue",
"errors": {

View File

@@ -261,10 +261,6 @@
"verify": {
"title": "Autenticar con una clave de acceso",
"description": "Tu dispositivo pedirá tu huella digital, rostro o bloqueo de pantalla",
"info": {
"description": "Usa la clave de acceso que configuraste para autenticarte de forma segura. ",
"link": "Más información sobre claves de acceso"
},
"usePassword": "Usar contraseña",
"submit": "Continuar",
"errors": {

View File

@@ -261,10 +261,6 @@
"verify": {
"title": "Autenticati con una passkey",
"description": "Il tuo dispositivo chiederà la tua impronta digitale, il volto o il blocco schermo",
"info": {
"description": "Usa la passkey che hai configurato per autenticarti in modo sicuro. ",
"link": "Scopri di più sulle Passkey"
},
"usePassword": "Usa password",
"submit": "Continua",
"errors": {

View File

@@ -261,10 +261,6 @@
"verify": {
"title": "Uwierzytelnij się za pomocą klucza dostępu",
"description": "Twoje urządzenie poprosi o użycie odcisku palca, rozpoznawania twarzy lub blokady ekranu.",
"info": {
"description": "Użyj skonfigurowanego klucza dostępu, aby bezpiecznie się uwierzytelnić. ",
"link": "Dowiedz się więcej o kluczach dostępu"
},
"usePassword": "Użyj hasła",
"submit": "Kontynuuj",
"errors": {

View File

@@ -261,10 +261,6 @@
"verify": {
"title": "Аутентификация с помощью пасскей",
"description": "Устройство запросит отпечаток пальца, лицо или экранный замок",
"info": {
"description": "Используйте настроенную пасскей для безопасной аутентификации. ",
"link": "Узнать больше о пасскеях"
},
"usePassword": "Использовать пароль",
"submit": "Продолжить",
"errors": {

View File

@@ -261,10 +261,6 @@
"verify": {
"title": "使用密钥认证",
"description": "您的设备将请求指纹、面部识别或屏幕锁",
"info": {
"description": "使用您设置的密钥进行安全认证。",
"link": "了解更多关于密钥"
},
"usePassword": "使用密码",
"submit": "继续",
"errors": {

View File

@@ -1,4 +1,4 @@
import { Alert, AlertType } from "@/components/alert";
import { Alert } from "@/components/alert";
import { DynamicTheme } from "@/components/dynamic-theme";
import { LoginPasskey } from "@/components/login-passkey";
import { Translated } from "@/components/translated";
@@ -71,24 +71,13 @@ export default async function Page(props: { searchParams: Promise<Record<string
</div>
<div className="w-full">
<Alert type={AlertType.INFO}>
<span>
<Translated i18nKey="verify.info.description" namespace="passkey" />
<a
className="text-primary-light-500 hover:text-primary-light-300 dark:text-primary-dark-500 hover:dark:text-primary-dark-300"
target="_blank"
href="https://zitadel.com/docs/guides/manage/user/reg-create-user#with-passwordless"
>
<Translated i18nKey="verify.info.link" namespace="passkey" />
</a>
</span>
</Alert>
{!(loginName || sessionId) ? (
{!(loginName || sessionId) && (
<Alert>
<Translated i18nKey="unknownContext" namespace="error" />
</Alert>
) : (
)}
{(loginName || sessionId) && (
<LoginPasskey
loginName={loginName}
sessionId={sessionId}

View File

@@ -65,6 +65,7 @@ export function LoginPasskey({ loginName, sessionId, requestId, altPassword, org
setLoading(false);
});
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
async function updateSessionForChallenge(
@@ -144,7 +145,7 @@ export function LoginPasskey({ loginName, sessionId, requestId, altPassword, org
listItem.id = coerceToArrayBuffer(listItem.id, "publicKey.allowCredentials.id");
});
navigator.credentials
return navigator.credentials
.get({
publicKey,
})