spinny:~/writing $ vim passkeys-webauthn-passwordless-authentication.md
1~2Le password sono una di quelle cose che abbiamo normalizzato solo perché ci conviviamo da anni. Gli utenti le dimenticano, le riusano, le scrivono dove non dovrebbero. I team devono gestire reset, policy, hash, leak, phishing e supporto.3~4Le passkey non rendono l'autenticazione perfetta, ma tolgono di mezzo un problema enorme: il server non deve più custodire un segreto condiviso con l'utente.5~6## Cosa succede davvero7~8Una passkey è una credenziale basata su WebAuthn. Quando l'utente la crea, il dispositivo genera una coppia di chiavi:9~10- una chiave privata, che resta sul dispositivo o nel password manager;11- una chiave pubblica, che il server può salvare.12~13Al login il server non chiede "dimmi la password". Manda una challenge casuale. Il dispositivo la firma con la chiave privata. Il server verifica la firma con la chiave pubblica.14~15Questa è la parte bella: se il database viene rubato, dentro non ci sono password da crackare. E se un utente finisce su un dominio falso, la passkey non è valida per quel dominio. Non è solo comodità, è una protezione concreta contro il phishing.16~17## Il browser fa da ponte18~19Nel browser le due API principali sono:20~21- `navigator.credentials.create()` per creare una passkey;22- `navigator.credentials.get()` per usarla durante il login.23~24Ma la logica importante sta sul server. Il server deve generare la challenge, salvarla temporaneamente, verificare la risposta, controllare origine e Relying Party ID, poi creare la sessione.25~26La parte client dovrebbe essere quasi noiosa:27~28```typescript29const options = await fetch('/api/passkeys/login/options').then((r) => r.json());30~31const credential = await navigator.credentials.get({32 publicKey: PublicKeyCredential.parseRequestOptionsFromJSON(options),33});34~35await fetch('/api/passkeys/login/verify', {36 method: 'POST',37 headers: { 'Content-Type': 'application/json' },38 body: JSON.stringify(credential?.toJSON()),39});40```41~42Se ti ritrovi a implementare a mano la crittografia WebAuthn, fermati. Usa una libreria solida lato server. Gli errori qui non sono "bug carini", sono buchi di autenticazione.43~44## Cosa salvare nel database45~46Non serve salvare mezzo mondo. Di solito bastano:47~48- ID della credenziale;49- chiave pubblica;50- utente collegato;51- eventuale counter o metadati di verifica;52- transports, se utili alla UX;53- nome scelto dall'utente;54- data di creazione e ultimo utilizzo.55~56Una tabella minima può assomigliare a questa:57~58```sql59create table passkey_credentials (60 id uuid primary key default gen_random_uuid(),61 user_id uuid not null references users(id),62 credential_id text not null unique,63 public_key text not null,64 name text,65 created_at timestamptz not null default now(),66 last_used_at timestamptz67);68```69~70Poi aggiungerei audit log e notifiche: se qualcuno crea una nuova passkey sul mio account, voglio saperlo.71~72## La UX conta più della demo73~74La demo di una passkey è sempre bellissima: clicchi, Face ID, sei dentro. Il prodotto reale è più complicato.75~76Qualcuno cambia telefono. Qualcuno usa un computer aziendale bloccato. Qualcuno non capisce perché il browser propone una passkey. Qualcuno perde accesso al proprio dispositivo.77~78Per questo non partirei con "da oggi niente più password per tutti". Partirei così:79~801. passkey opzionali per utenti interni;812. suggerimento di crearne una dopo un login riuscito;823. pagina account per rinominare e rimuovere passkey;834. fallback chiaro;845. rollout graduale nel login principale.85~86Il testo nell'interfaccia deve essere semplice. "Usa il blocco schermo del tuo dispositivo" è meglio di "autenticati con una credenziale FIDO2 residente".87~88## Errori che eviterei89~90Non generare challenge sul client. La challenge nasce sul server e deve essere verificata una sola volta.91~92Non fidarti solo del credential ID. Devi verificare firma, challenge, origine e Relying Party ID.93~94Non cancellare i fallback prima di avere un buon recovery flow. Passwordless non deve diventare "se perdi il telefono sei fuori per sempre".95~96Non trattare la passkey come un bottone puramente frontend. Nascondere un pulsante non è sicurezza: la verifica vera è server-side.97~98## Passkey-first o passkey-friendly?99~100Per un prodotto nuovo puoi pensare passkey-first. Per un'app esistente io preferisco passkey-friendly: aggiungi passkey come metodo consigliato, misuri successo e problemi, poi riduci il peso delle password con calma.101~102La migrazione ideale non si sente. L'utente scopre che accedere è più semplice, non che l'azienda ha cambiato protocollo di autenticazione.103~104## Conclusione105~106Le passkey sono interessanti perché migliorano sicurezza e UX nello stesso momento, cosa rara. Non sono una bacchetta magica: recovery, compatibilità, supporto e rollout restano da progettare bene.107~108Però il cambio di base è forte. Smetti di chiedere agli utenti di inventare e proteggere segreti. Lasci che il dispositivo firmi una prova crittografica legata al tuo dominio. Meno memoria umana, meno phishing, meno reset password. Direi che vale la pena prenderle sul serio.109~110## Fonti111~112- [MDN: Passkeys](https://developer.mozilla.org/en-US/docs/Web/Security/Authentication/Passkeys)113- [MDN: Web Authentication API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Authentication_API)114- [W3C: Web Authentication](https://www.w3.org/TR/webauthn-3/)115- [passkeys.dev](https://passkeys.dev/)116~
NORMAL · passkeys-webauthn-passwordless-authentication.md [readonly]116 lines · :q to close