spinny:~/writing $ less passkeys-webauthn-passwordless-authentication.md
12Le 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.34Le 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.56## Cosa succede davvero78Una passkey è una credenziale basata su WebAuthn. Quando l'utente la crea, il dispositivo genera una coppia di chiavi:910- una chiave privata, che resta sul dispositivo o nel password manager;11- una chiave pubblica, che il server può salvare.1213Al 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.1415Questa è 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.1617## Il browser fa da ponte1819Nel browser le due API principali sono:2021- `navigator.credentials.create()` per creare una passkey;22- `navigator.credentials.get()` per usarla durante il login.2324Ma 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.2526La parte client dovrebbe essere quasi noiosa:2728```typescript29const options = await fetch('/api/passkeys/login/options').then((r) => r.json());3031const credential = await navigator.credentials.get({32 publicKey: PublicKeyCredential.parseRequestOptionsFromJSON(options),33});3435await fetch('/api/passkeys/login/verify', {36 method: 'POST',37 headers: { 'Content-Type': 'application/json' },38 body: JSON.stringify(credential?.toJSON()),39});40```4142Se 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.4344## Cosa salvare nel database4546Non serve salvare mezzo mondo. Di solito bastano:4748- 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.5556Una tabella minima può assomigliare a questa:5758```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```6970Poi aggiungerei audit log e notifiche: se qualcuno crea una nuova passkey sul mio account, voglio saperlo.7172## La UX conta più della demo7374La demo di una passkey è sempre bellissima: clicchi, Face ID, sei dentro. Il prodotto reale è più complicato.7576Qualcuno cambia telefono. Qualcuno usa un computer aziendale bloccato. Qualcuno non capisce perché il browser propone una passkey. Qualcuno perde accesso al proprio dispositivo.7778Per questo non partirei con "da oggi niente più password per tutti". Partirei così:79801. 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.8586Il testo nell'interfaccia deve essere semplice. "Usa il blocco schermo del tuo dispositivo" è meglio di "autenticati con una credenziale FIDO2 residente".8788## Errori che eviterei8990Non generare challenge sul client. La challenge nasce sul server e deve essere verificata una sola volta.9192Non fidarti solo del credential ID. Devi verificare firma, challenge, origine e Relying Party ID.9394Non cancellare i fallback prima di avere un buon recovery flow. Passwordless non deve diventare "se perdi il telefono sei fuori per sempre".9596Non trattare la passkey come un bottone puramente frontend. Nascondere un pulsante non è sicurezza: la verifica vera è server-side.9798## Passkey-first o passkey-friendly?99100Per 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.101102La migrazione ideale non si sente. L'utente scopre che accedere è più semplice, non che l'azienda ha cambiato protocollo di autenticazione.103104## Conclusione105106Le 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.107108Però 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.109110## Fonti111112- [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
:Passkey e WebAuthn: login senza password, senza magialines 1-116 (END) — press q to close