Accedere con una passkey tramite la compilazione automatica dei moduli

Creare un'esperienza di accesso che utilizzi le passkey, pur supportando 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. L'utilizzo della compilazione automatica dei moduli per suggerire le passkey può contribuire a creare un'esperienza unificata.

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

Con una passkey, un utente può accedere a un sito web semplicemente utilizzando l'impronta, il volto o il PIN del dispositivo.

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

Tuttavia, il passaggio dall'autenticazione basata su password a quella basata su passkey può essere difficile. Quando gli utenti passeranno alle passkey, ci saranno ancora quelli che useranno le password e i siti web dovranno soddisfare entrambi i tipi di utenti. Non si deve pretendere che gli utenti ricordino su quali siti hanno iniziato a utilizzare le passkey, quindi chiedere loro di selezionare in anticipo il metodo da utilizzare non sarebbe un'esperienza utente ottimale.

Anche le passkey sono una nuova tecnologia. Spiegarli e assicurarsi che gli utenti se ne servano con disinvoltura può essere una sfida per i siti web. Possiamo contare su esperienze utente note per la compilazione automatica delle password, in modo da risolvere entrambi i problemi.

Interfaccia utente condizionale

Per creare un'esperienza utente efficiente sia per gli utenti con passkey che per quelli con password, puoi includere le passkey nei suggerimenti di compilazione automatica. Si tratta dell'interfaccia utente 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 con suggerimenti di compilazione automatica che mette in evidenza le passkey memorizzate insieme ai suggerimenti di compilazione automatica della password. L'utente può quindi scegliere un account e utilizzare 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 della sicurezza delle passkey, se ne hanno una.

Come funziona

Per autenticarti con una passkey, utilizza l'API WebAuthn.

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

  • Backend: il server di backend che contiene il database degli account che memorizza 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'app di autenticazione dell'utente che crea e memorizza la passkey. Può trovarsi sullo stesso dispositivo del browser (ad esempio quando utilizzi Windows Hello) o su un altro dispositivo, come uno smartphone.
Diagramma di autenticazione con passkey
  1. Non appena un utente arriva sul frontend, richiede una verifica dal backend per autenticarsi con una passkey e chiama navigator.credentials.get() per avviare l'autenticazione con una passkey. Viene restituito un Promise.
  2. Quando l'utente posiziona il cursore nel campo di accesso, il browser mostra una finestra di dialogo di compilazione automatica della password che include le passkey. Viene visualizzata una finestra di dialogo di autenticazione se l'utente seleziona una passkey.
  3. Dopo che l'utente ha verificato la propria identità utilizzando il blocco schermo del dispositivo, la promessa viene risolta e una credenziale con chiave pubblica viene restituita al frontend.
  4. Il frontend invia la credenziale della chiave pubblica al backend. Il backend verifica la firma rispetto alla chiave pubblica dell'account associato nel database. Se l'operazione va a buon fine, l'utente ha eseguito l'accesso.

Autenticazione con una passkey tramite compilazione automatica dei moduli

Quando un utente vuole accedere, puoi effettuare una chiamata WebAuthn get condizionale 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 risolve la promessa con una credenziale anziché compilare il modulo di accesso. È responsabilità della pagina far accedere l'utente.

Annotare il campo di immissione del modulo

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

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

Rilevamento di funzionalità

Prima di invocare una chiamata all'API WebAuthn condizionale, controlla se:

  • Il browser supporta WebAuthn con PublicKeyCredential.

Supporto dei browser

  • Chrome: 67.
  • Edge: 18.
  • Firefox: 60.
  • Safari: 13.

Origine

Supporto dei browser

  • Chrome: 108.
  • Edge: 108.
  • Firefox: 119.
  • Safari: 16.

Origine

// 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  
  }  
}  

Recupera una sfida dal server RP

Recupera una sfida dal server RP necessaria per chiamare navigator.credentials.get():

  • challenge: una verifica generata dal server in un ArrayBuffer. Questa operazione è necessaria per evitare attacchi di replay. Assicurati di generare una nuova verifica a ogni tentativo di accesso e di ignorarla dopo una determinata durata o dopo che un tentativo di accesso non è andato a buon fine. Puoi considerarlo 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. Impostalo su "preferred" o ometti la proprietà.

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

Chiama navigator.credentials.get() per iniziare ad attendere l'autenticazione 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 sufisso registrabile. Questo valore deve corrispondere all'attributo rp.id utilizzato al momento della creazione della passkey.

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

Invia la credenziale della chiave pubblica restituita al server RP

Dopo che l'utente ha selezionato un account e ha dato il consenso 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 della credenziale della chiave pubblica contiene le seguenti proprietà:

  • id: l'ID con codifica base64url della credenziale della passkey autenticata.
  • rawId: una versione ArrayBuffer dell'ID credenziale.
  • response.clientDataJSON: un array di dati client. Questo campo contiene informazioni come la verifica e l'origine che il server RP dovrà verificare.
  • response.authenticatorData: un array di dati dell'autenticatore. 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. Questo valore può essere utilizzato, 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 la 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 bisogno di utilizzare un telefono per accedere, ti consigliamo di invitarlo a creare una passkey sul dispositivo locale.
  • type: questo campo è sempre impostato su "public-key".

Se utilizzi una libreria per gestire l'oggetto della credenziale con 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 della chiave pubblica sul server, passala alla biblioteca FIDO per elaborare l'oggetto.

Cerca l'ID credenziale corrispondente con la proprietà id. Se devi determinare l'account utente, utilizza la proprietà userHandle, ovvero user.id specificato durante la creazione della credenziale. Verifica se il valore signature della credenziale può essere verificato con la chiave pubblica archiviata. Per farlo, ti consigliamo di utilizzare una libreria lato server o una soluzione anziché scrivere il tuo codice. Puoi trovare le librerie open source nel repository GitHub di awesome-webauth.

Una volta verificata la credenziale con una chiave pubblica corrispondente, fai accedere l'utente.

Segui istruzioni più dettagliate nella pagina Autentificazione con passkey lato server

Risorse