Skip to content

Developer notes

  • Add-on id kv_passkey_login, tables kv_pkl_users, kv_pkl_factors, kv_pkl_challenges, kv_pkl_rate, kv_pkl_log, namespace Tygh\Addons\KvPasskeyLogin.
  • Generated from the Login Security: 2FA & Passkeys code base (addons/login_security_2fa/editions/build.py + editions/passkey_login/): same WebAuthn verifier (CBOR/COSE, ES256 + RS256, attestation none and packed accepted without trust), no second step, no authenticator apps, recovery codes or trusted devices.
  • Ceremonies: kv_passkey_login.login_options / kv_passkey_login.login (storefront, POST, JSON), auth.kv_pkl_login_options / auth.kv_pkl_login (panel); single-use challenges (5 minutes, bound to the session and the host), origin and RP ID checks, user verification required for passwordless sign-in, discoverable credentials with a random user handle per user, signature counter check, failed attempts rate-limited per IP.
  • Autofill: navigator.credentials.get({mediation: 'conditional'}) for a visible sign-in form; a hidden header pop-up starts its request when its e-mail field gets the focus, so guest page views create no challenge rows.
  • PHP hooks: login_user_pre, post_delete_user, user_logout_after; template hooks index:login_buttons, profiles:account_update, profiles:my_account_menu, auth:login_form (admin), profiles:tabs_content; no core changes.
  • Full page cache: the button markup depends only on settings and the licence (same for every visitor); all per-visitor work happens in POST requests from JavaScript.
  • Edition::deferred() is true while kv_login_security_2fa is active; Importer copies passkeys and user handles into kv_ls2fa_* once (first admin request) and on demand, never deleting anything here.