{"record":{"id":"a15392e474ea4694","repo":"QuantumNous/new-api","slug":"failed-to-complete-passkey-login","errorCode":null,"errorMessage":"Failed to complete Passkey login","messagePattern":"Failed to complete Passkey login","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"web/src/features/auth/sign-in/components/user-auth-form.tsx","lineNumber":291,"sourceCode":"\n      const credential = (await navigator.credentials.get({\n        publicKey,\n      })) as PublicKeyCredential | null\n\n      if (!credential) {\n        toast.info(t('Passkey login was cancelled'))\n        return\n      }\n\n      const assertion = buildAssertionResult(credential)\n      if (!assertion) {\n        throw new Error(t('Invalid Passkey response'))\n      }\n\n      const finish = await finishPasskeyLogin(flowToken, assertion)\n      if (!finish.success) {\n        if (getServerErrorMessageKey(finish)) return\n        throw new Error(finish.message || t('Failed to complete Passkey login'))\n      }\n\n      if (!isAuthBundle(finish.data)) {\n        throw new Error(t('Missing user data from Passkey login response'))\n      }\n\n      await handleLoginSuccess(finish.data, redirectTo)\n      toast.success(t('Signed in with Passkey'))\n    } catch (error: unknown) {\n      if (getServerErrorMessageKey(error)) return\n      if (error instanceof DOMException && error.name === 'NotAllowedError') {\n        toast.info(t('Passkey login was cancelled or timed out'))\n      } else if (error instanceof Error) {\n        toast.error(error.message)\n      } else {\n        toast.error(t('Passkey login failed'))\n      }\n    } finally {","sourceCodeStart":273,"sourceCodeEnd":309,"githubUrl":"https://github.com/QuantumNous/new-api/blob/e2c7aa7b102c2075eae2377df3508658d45e88dc/web/src/features/auth/sign-in/components/user-auth-form.tsx#L273-L309","documentation":"Thrown in the Passkey sign-in flow when finishPasskeyLogin — the POST that submits the signed WebAuthn assertion with the flow_token — returns success:false without a handled server message key. The fallback text is 'Failed to complete Passkey login'; the server's own message wins when present. This is a server-side verification failure of the assertion.","triggerScenarios":"POST finish-passkey-login returns success:false: challenge mismatch, expired flow_token, unknown credential ID, signature verification failure, or clock skew between server and authenticator.","commonSituations":"User left the WebAuthn prompt open until the flow_token expired; credential deleted server-side but still present in the browser; backend RPC to the WebAuthn verifier failing; server time drift breaking challenge timestamps.","solutions":["Read finish.message from the response — the backend states the verification failure reason.","Retry the whole Passkey flow promptly (fresh challenge + flow_token); most failures are stale-token timing issues.","If it persists for one device, re-register the passkey (delete then add) — server-side credential state may be stale.","Check server logs/clock sync if all users are affected."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  const finish = await finishPasskeyLogin(flowToken, assertion)\n  if (!finish.success) {\n    if (getServerErrorMessageKey(finish)) return\n    throw new Error(finish.message || t('Failed to complete Passkey login'))\n  }\n} catch (error) {\n  if (getServerErrorMessageKey(error)) return\n  if (error instanceof DOMException && error.name === 'NotAllowedError') {\n    toast.info(t('Passkey login was cancelled or timed out'))\n  } else {\n    toast.error(error instanceof Error ? error.message : t('Passkey login failed'))\n  }\n}","preventionTips":["Finish the WebAuthn ceremony quickly — stale flow tokens are the top cause","If a device keeps failing verification, re-register its passkey","Keep server clocks NTP-synced for challenge validity windows"],"tags":["passkey","webauthn","assertion-verification","login"],"backgroundTag":null,"analyzedSha":"e2c7aa7b102c2075eae2377df3508658d45e88dc","analyzedAt":"2026-08-15T10:35:18.111Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}