Implementing Passwordless Authentication

1. Understanding Passwordless Concepts

MethodFactor UsedPhish-Resistant?
Magic linkEmail possessionPartial
SMS codePhone possessionNo (SIM swap)
WebAuthn / PasskeysDevice key + biometricYes
Hardware keyPossession + PINYes
Biometric onlyInherence (device-bound)Yes
  1. User enters email
  2. Generate token (32 bytes), store hash + expiry (10 min)
  3. Email link: https://app/auth/verify?t=<raw>
  4. User clicks → server verifies + consumes token
  5. Issue session/JWT → redirect to app
  6. Bind token to originating IP/UA to prevent forwarding

3. Implementing WebAuthn

Example: Browser registration

const cred = await navigator.credentials.create({
  publicKey: {
    challenge: base64url.decode(serverChallenge),
    rp: { id: "example.com", name: "Acme" },
    user: { id: userIdBytes, name: "alice@x.com", displayName: "Alice" },
    pubKeyCredParams: [{ type: "public-key", alg: -7 }, { alg: -257 }],
    authenticatorSelection: { residentKey: "required", userVerification: "preferred" },
    attestation: "none"
  }
});
// POST cred to /webauthn/register/finish → server verifies + stores publicKey
AlgorithmCOSE ID
ES256 (recommended)-7
RS256-257
EdDSA-8

4. Using Biometric Authentication

Where UsedStack
Native iOSLocalAuthentication framework
Native AndroidBiometricPrompt API
WebWebAuthn platform authenticator (Touch ID, Hello, Android)
StoragePrivate key in Secure Enclave / StrongBox / TPM

5. Implementing SMS Magic Codes

AspectDetail
Code6 digits
Validity5 min
Autofill (iOS)Append @example.com #123456
Autofill (Android)App-signature hash in message

6. Using Hardware Security Keys

ConnectorUse
USB-A / USB-CDesktop, laptop
NFCMobile (Android, iOS)
LightningiPhone (older)
BluetoothMulti-device (less common)
ProtocolFIDO2 (CTAP2) + WebAuthn

7. Implementing Passkeys

AspectDetail
DefinitionFIDO2 discoverable credential synced across devices
SynciCloud Keychain, Google Password Manager, 1Password, Bitwarden
UXUsername field shows passkey suggestion (Conditional UI)
ServerStandard WebAuthn — same code path
Cross-deviceQR + Bluetooth handoff (hybrid transport)
ReplacesPasswords + TOTP in single phish-resistant flow

8. Handling Device Registration Flow

Passkey Registration

  1. Authenticate user with existing factor (or after signup)
  2. Server generates challenge (32 bytes), stores in session
  3. Send PublicKeyCredentialCreationOptions to client
  4. Client invokes navigator.credentials.create() — user authorizes via biometric
  5. Client returns attestation + public key to server
  6. Server verifies challenge, origin (RP ID), signature
  7. Store credentialId + publicKey + signCount + AAGUID

9. Implementing Fallback Mechanisms

PrimaryFallback
PasskeyMagic link to verified email
WebAuthn keyBackup codes
BiometricDevice PIN
All factors lostIdentity proofing (ID verification)

10. Using Conditional UI

Example: Autofill discoverable passkey

<input type="text" autocomplete="username webauthn">
// Quietly listen for selection — no button click required
const assertion = await navigator.credentials.get({
  mediation: "conditional",
  publicKey: { challenge: serverChallenge, rpId: "example.com" }
});