Accedere con una passkey tramite la compilazione automatica dei moduli

Crea un'esperienza di accesso che utilizzi le passkey, continuando ad accogliere gli utenti con password esistenti.

Le passkey sostituiscono le password e rendono gli account utente sul web più sicuri, semplici e facili da usare. Tuttavia, il passaggio dall'autenticazione basata su password a quella basata su passkey può complicare l'esperienza utente. Usare la compilazione automatica dei moduli per suggerire passkey può aiutare a creare un'esperienza unificata.

Perché usare la compilazione automatica dei moduli per accedere con una passkey?

Con una passkey è possibile accedere a un sito web utilizzando l'impronta, il volto o il PIN del dispositivo.

Idealmente, non ci sarebbero utenti di password e il flusso di autenticazione potrebbe essere semplice come un singolo pulsante di accesso. Quando l'utente tocca il pulsante, viene visualizzata una finestra di dialogo del selettore di account e l'utente può scegliere un account, sbloccare lo schermo per eseguire la verifica e accedere.

Tuttavia, la transizione dalla password all'autenticazione basata su passkey può essere difficile. Man mano che gli utenti passano alle passkey, ci saranno ancora coloro che utilizzano le password e i siti web dovranno soddisfare entrambi i tipi di utenti. Gli utenti non dovrebbero aspettarsi di ricordare su quali siti sono passati alle passkey, quindi chiedere agli utenti di selezionare in anticipo il metodo da usare risulterebbe scadente.

Anche le passkey sono una nuova tecnologia. Spiegarle e assicurarsi che gli utenti si sentano a proprio agio nel utilizzarli può essere difficile per i siti web. Compilando automaticamente le password, possiamo fare affidamento su esperienze utente familiari per risolvere entrambi i problemi.

UI condizionale

Per creare un'esperienza utente efficiente sia per gli utenti che utilizzano passkey che per le password, puoi includere passkey nei suggerimenti di compilazione automatica. Si tratta della cosiddetta UI condizionale e fa parte dello standard WebAuthn.

Non appena l'utente tocca il campo di immissione del nome utente, viene visualizzata una finestra di dialogo di suggerimenti di compilazione automatica che evidenzia le passkey memorizzate insieme ai suggerimenti di compilazione automatica delle password. L'utente può quindi scegliere un account e usare il blocco schermo del dispositivo per accedere.

In questo modo, gli utenti possono accedere al tuo sito web con il modulo esistente come se non fosse cambiato nulla, ma con il vantaggio aggiuntivo in termini di sicurezza delle passkey, se ne hanno una.

Come funziona

Per eseguire l'autenticazione con una passkey, utilizza l'API WebAuthn.

I quattro componenti di un flusso di autenticazione tramite passkey sono: l'utente:

  • Backend: il server di backend che contiene il database degli account in cui è archiviata la chiave pubblica e altri metadati sulla passkey.
  • Frontend: il frontend che comunica con il browser e invia richieste di recupero al backend.
  • Browser: il browser dell'utente su cui è in esecuzione JavaScript.
  • Authenticator: l'autenticatore dell'utente che crea e archivia la passkey. Potrebbe trovarsi sullo stesso dispositivo del browser (ad esempio quando usi Windows Hello) o su un altro dispositivo, ad esempio uno smartphone.
Diagramma dell'autenticazione con passkey
  1. Non appena un utente arriva sul frontend, richiede al backend una richiesta di autenticazione con una passkey e chiama navigator.credentials.get() per avviare l'autenticazione con una passkey. Viene restituito un valore Promise.
  2. Quando l'utente posiziona il cursore nel campo di accesso, il browser visualizza una finestra di dialogo di compilazione automatica delle password che include le passkey. Se l'utente seleziona una passkey, viene visualizzata una finestra di dialogo di autenticazione.
  3. Dopo che l'utente ha verificato la propria identità utilizzando il blocco schermo del dispositivo, la promessa viene risolta e viene restituita una credenziale di chiave pubblica al frontend.
  4. Il frontend invia la credenziale della chiave pubblica al backend. Il backend verifica la firma in base alla chiave pubblica dell'account corrispondente nel database. Se l'operazione va a buon fine, l'utente ha eseguito l'accesso.

Prerequisiti

La UI Conditional WebAuthn è supportata pubblicamente in Safari su iOS 16, iPadOS 16 e MacOS Ventura. È disponibile anche su Chrome su Android, macOS e Windows 11 22H2.

Esegui l'autenticazione con una passkey tramite la compilazione automatica dei moduli

Quando un utente vuole accedere, puoi effettuare una chiamata WebAuthn condizionale get per indicare che le passkey potrebbero essere incluse nei suggerimenti di compilazione automatica. Una chiamata condizionale all'API navigator.credentials.get() di WebAuthn non mostra l'interfaccia utente e rimane in attesa finché l'utente non sceglie un account con cui accedere dai suggerimenti di compilazione automatica. Se l'utente sceglie una passkey, il browser risolverà la promessa con una credenziale anziché compilare il modulo di accesso. Sarà quindi responsabilità della pagina eseguire l'accesso all'utente.

Campo di immissione del modulo per l'annotazione

Se necessario, aggiungi un attributo autocomplete al campo del nome utente input. Aggiungi username e webauthn come token per consentire di suggerire passkey.

<input type="text" name="username" autocomplete="username webauthn" ...>

Rilevamento delle funzionalità

Prima di richiamare una chiamata API WebAuthn condizionale, verifica se:

  • Il browser supporta WebAuthn.
  • Il browser supporta l'interfaccia utente condizionale WebAuthn.
// Availability of `window.PublicKeyCredential` means WebAuthn is usable.  
if (window.PublicKeyCredential &&  
    PublicKeyCredential.​​isConditionalMediationAvailable) {  
  // Check if conditional mediation is available.  
  const isCMA = await PublicKeyCredential.​​isConditionalMediationAvailable();  
  if (isCMA) {  
    // Call WebAuthn authentication  
  }  
}  

Recupero di una verifica dal server RP

Recupero dal server RP necessario per chiamare navigator.credentials.get():

  • challenge: una richiesta di verifica generata dal server in un ArrayBuffer. Questa operazione è necessaria per prevenire gli attacchi ripetuti. Assicurati di generare una nuova verifica a ogni tentativo di accesso e ignorala dopo un determinato periodo di tempo o quando un tentativo di accesso non riesce a essere convalidato. Consideralo un token CSRF.
  • allowCredentials: un array di credenziali accettabili per questa autenticazione. Passa un array vuoto per consentire all'utente di selezionare una passkey disponibile da un elenco mostrato dal browser.
  • userVerification: indica se la verifica dell'utente tramite il blocco schermo del dispositivo è "required", "preferred" o "discouraged". Il valore predefinito è "preferred", il che significa che l'autenticatore potrebbe saltare la verifica dell'utente. Imposta questo elemento su "preferred" oppure ometti la proprietà.

Chiama l'API WebAuthn con il flag conditional per autenticare l'utente

Chiama il numero navigator.credentials.get() per iniziare ad attendere l'autenticazione dell'utente.

// To abort a WebAuthn call, instantiate an `AbortController`.
const abortController = new AbortController();

const publicKeyCredentialRequestOptions = {
  // Server generated challenge
  challenge: ****,
  // The same RP ID as used during registration
  rpId: 'example.com',
};

const credential = await navigator.credentials.get({
  publicKey: publicKeyCredentialRequestOptions,
  signal: abortController.signal,
  // Specify 'conditional' to activate conditional UI
  mediation: 'conditional'
});
  • rpId: Un ID RP è un dominio e un sito web può specificare il proprio dominio o un suffisso registrabile. Questo valore deve corrispondere al valore rp.id utilizzato quando è stata creata la passkey.

Ricordati di specificare mediation: 'conditional' per rendere condizionale la richiesta.

Invia la credenziale di chiave pubblica restituita al server RP

Dopo che l'utente ha selezionato un account e acconsentito utilizzando il blocco schermo del dispositivo, la promessa viene risolta restituendo un oggetto PublicKeyCredential al frontend RP.

Una promessa può essere rifiutata per diversi motivi. Devi gestire gli errori di conseguenza, a seconda della proprietà name dell'oggetto Error:

  • NotAllowedError: l'utente ha annullato l'operazione.
  • Altre eccezioni: si è verificato un problema imprevisto. Il browser mostra all'utente una finestra di dialogo di errore.

L'oggetto delle credenziali di chiave pubblica contiene le seguenti proprietà:

  • id: L'ID codificato in base64url della credenziale di passkey autenticata.
  • rawId: una versione ArrayBuffer dell'ID credenziale.
  • response.clientDataJSON: un ArrayBuffer di dati del client. Questo campo contiene informazioni come il problema e l'origine che il server RP dovrà verificare.
  • response.authenticatorData: un ArrayBuffer di dati di autenticazione. Questo campo contiene informazioni come l'ID RP.
  • response.signature: un ArrayBuffer della firma. Questo valore è il nucleo della credenziale e deve essere verificato sul server.
  • response.userHandle: un ArrayBuffer contenente l'ID utente impostato al momento della creazione. È possibile utilizzare questo valore, al posto dell'ID credenziale, se il server deve scegliere i valori ID che utilizza o se il backend vuole evitare di creare un indice sugli ID credenziali.
  • authenticatorAttachment: restituisce platform quando questa credenziale proviene dal dispositivo locale. In caso contrario cross-platform, in particolare quando l'utente ha utilizzato un telefono per accedere. Se l'utente ha dovuto utilizzare un telefono per accedere, potresti invitarlo a creare una passkey sul dispositivo locale.
  • type: questo campo è sempre impostato su "public-key".

Se utilizzi una libreria per gestire l'oggetto credenziali di chiave pubblica sul server RP, ti consigliamo di inviare l'intero oggetto al server dopo averlo codificato parzialmente con base64url.

Verifica la firma

Quando ricevi la credenziale di chiave pubblica sul server, passala alla libreria FIDO per elaborare l'oggetto.

Cerca l'ID credenziale corrispondente con la proprietà id (se devi determinare l'account utente, utilizza la proprietà userHandle, che è il user.id specificato durante la creazione della credenziale). Vedi se è possibile verificare signature delle credenziali con la chiave pubblica archiviata. Per farlo, consigliamo di usare una soluzione o una libreria lato server, anziché scrivere il tuo codice. Puoi trovare le librerie open source nel repository GitHub fantastico-webauth.

Dopo aver verificato la credenziale con una chiave pubblica corrispondente, fai accedere l'utente.

Risorse