diff --git a/src/components/AuthorizerPasskeyLogin.tsx b/src/components/AuthorizerPasskeyLogin.tsx
index 0df930c..bb29d1e 100644
--- a/src/components/AuthorizerPasskeyLogin.tsx
+++ b/src/components/AuthorizerPasskeyLogin.tsx
@@ -13,6 +13,33 @@ import { Message } from './Message';
// WebAuthn JSON ceremony APIs the SDK relies on - there is no server-side
// config flag for passkeys (unlike social login), it's purely a browser
// capability.
+// PasskeyIcon is an inline fingerprint glyph (no icon-library dependency) that
+// inherits the button's text color via currentColor.
+const PasskeyIcon: FC = () => (
+
+);
+
export const AuthorizerPasskeyLogin: FC<{
onLogin?: (data: AuthToken | void) => void;
}> = ({ onLogin }) => {
@@ -47,13 +74,24 @@ export const AuthorizerPasskeyLogin: FC<{
const hasAnotherLoginMethod =
hasSocialLogin || hasBasicAuthLogin || config.is_magic_link_login_enabled;
+ // A cancelled ceremony or an account with no passkey surfaces as
+ // NotAllowedError/AbortError (the browser deliberately does not distinguish
+ // "cancelled" from "no credential" to avoid leaking account state). Neither is
+ // a real failure - the user simply falls back to password/social login - so we
+ // dismiss silently instead of showing a scary error banner. The button is
+ // always visible when the browser supports WebAuthn, so this path is common.
+ const isUserDismissed = (e?: { code?: string }): boolean =>
+ e?.code === `NotAllowedError` || e?.code === `AbortError`;
+
const onClick = async () => {
setError(``);
try {
setLoading(true);
const { data: res, errors } = await authorizerRef.loginWithPasskey();
if (errors && errors.length) {
- setError(errors[0]?.message || ``);
+ if (!isUserDismissed(errors[0])) {
+ setError(errors[0]?.message || ``);
+ }
return;
}
if (res) {
@@ -68,7 +106,9 @@ export const AuthorizerPasskeyLogin: FC<{
onLogin(res);
}
} catch (err) {
- setError((err as Error).message);
+ if (!isUserDismissed(err as { code?: string })) {
+ setError((err as Error).message);
+ }
} finally {
setLoading(false);
}
@@ -86,7 +126,17 @@ export const AuthorizerPasskeyLogin: FC<{
disabled={loading}
appearance={ButtonAppearance.Default}
>
- {loading ? `Waiting for passkey ...` : `Sign in with a passkey`}
+
+
+ {loading ? `Waiting for passkey ...` : `Sign in with a passkey`}
+
{hasAnotherLoginMethod && OR}
>