Approfondimento sulle credenziali rilevabili

Anche se le credenziali FIDO, come le passkey, hanno lo scopo di sostituire le password, la maggior parte di esse può anche evitare che l'utente digiti il nome utente. In questo modo gli utenti possono autenticarsi selezionando un account da un elenco di passkey per il sito web corrente.

Le versioni precedenti dei token di sicurezza erano state progettate come metodi di autenticazione in due passaggi e richiedevano gli ID delle potenziali credenziali, pertanto richiedevano l'inserimento di un nome utente. Credenziali che un token di sicurezza può trovare senza sapere che i relativi ID sono chiamati credenziali rilevabili. La maggior parte delle credenziali FIDO create oggi sono credenziali rilevabili, in particolare le passkey archiviate in un gestore delle password o su un token di sicurezza moderno.

Per assicurarti che le credenziali siano rilevabili, specifica residentKey e requireResidentKey quando viene creata la passkey.

I fiduciari (RP) possono usare credenziali rilevabili omettendo allowCredentials durante l'autenticazione tramite passkey. In questi casi, il browser o il sistema mostra all'utente un elenco di passkey disponibili, identificate dalla proprietà user.name impostata al momento della creazione. Se l'utente ne seleziona uno, il valore user.id verrà incluso nella firma risultante. Il server può quindi utilizzare quell'ID credenziale restituito o l'ID credenziale restituito per cercare l'account invece di un nome utente digitato.

Le UI del selettore di account, come quelle descritte in precedenza, non mostrano mai credenziali non rilevabili.

requireResidentKey e residentKey

Per creare una credenziale rilevabile, specifica authenticatorSelection.residentKey e authenticatorSelection.requireResidentKey su navigator.credentials.create() con i valori indicati come segue.

async function register () {
  // ...

  const publicKeyCredentialCreationOptions = {
    // ...
    authenticatorSelection: {
      authenticatorAttachment: 'platform',
      residentKey: 'required',
      requireResidentKey: true,
    }
  };

  const credential = await navigator.credentials.create({
    publicKey: publicKeyCredentialCreationOptions
  });

  // This does not run until the user selects a passkey.
  const credential = {};
  credential.id = cred.id;
  credential.rawId = cred.id; // Pass a Base64URL encoded ID string.
  credential.type = cred.type;

  // ...
}

residentKey:

  • 'required': è necessario creare una credenziale rilevabile. Se non è possibile crearlo, viene restituito NotSupportedError.
  • 'preferred': la parte soggetta a limitazioni preferisce creare una credenziale rilevabile, ma accetta una credenziale non rilevabile.
  • 'discouraged': la parte soggetta a limitazioni preferisce creare una credenziale non rilevabile, ma accetta una credenziale rilevabile.

requireResidentKey:

  • Questa proprietà viene mantenuta per garantire la compatibilità con le versioni precedenti di WebAuthn livello 1, una versione precedente della specifica. Imposta questo valore su true se residentKey è 'required', altrimenti impostalo su false.

allowCredentials

I RP possono usare allowCredentials su navigator.credentials.get() per controllare l'esperienza di autenticazione tramite passkey. In genere esistono tre tipi di esperienze di autenticazione tramite passkey:

Con le credenziali rilevabili, le parti soggette a limitazioni possono mostrare un selettore di account modale per consentire all'utente di selezionare un account con cui accedere, seguito dalla verifica dell'utente. È adatto al flusso di autenticazione tramite passkey che viene avviato premendo un pulsante dedicato all'autenticazione tramite passkey.

Per ottenere questa esperienza utente, ometti o passa un array vuoto al parametro allowCredentials in navigator.credentials.get().

async function authenticate() {
  // ...

  const publicKeyCredentialRequestOptions = {
    // Server generated challenge:
    challenge: ****,
    // The same RP ID as used during registration:
    rpId: 'example.com',
    // You can omit `allowCredentials` as well:
    allowCredentials: []
  };

  const credential = await navigator.credentials.get({
    publicKey: publicKeyCredentialRequestOptions,
    signal: abortController.signal
  });

  // This does not run until the user selects a passkey.
  const credential = {};
  credential.id = cred.id;
  credential.rawId = cred.id; // Pass a Base64URL encoded ID string.
  credential.type = cred.type;
  
  // ...
}

Mostra la compilazione automatica dei moduli tramite passkey

Il selettore di account modale descritto sopra funziona bene se la maggior parte degli utenti utilizza le passkey e le ha a disposizione sul dispositivo locale. Per un utente che non dispone di passkey locali, viene comunque visualizzata la finestra di dialogo modale e gli verrà chiesto di presentare una passkey da un altro dispositivo. Durante la transizione degli utenti alle passkey, ti consigliamo di evitare questa UI per gli utenti che non l'hanno configurata.

La selezione di una passkey può invece essere inclusa nelle richieste di compilazione automatica per i campi di un modulo di accesso tradizionale, insieme a nomi utente e password salvati. In questo modo, un utente con passkey può "compilare" il modulo di accesso selezionando la passkey, gli utenti con coppie nome utente e password salvate potranno selezionarle e gli utenti senza nessuna delle due potranno comunque digitare il proprio nome utente e la password.

Questa esperienza utente è ideale quando la parte soggetta a limitazioni è in fase di migrazione con un utilizzo misto di password e passkey.

Per ottenere questa esperienza utente, oltre a passare un array vuoto alla proprietà allowCredentials o omettere il parametro, specifica mediation: 'conditional' su navigator.credentials.get() e annota un campo di immissione HTML username con autocomplete="username webauthn" o un campo di immissione password con autocomplete="password webauthn".

La chiamata all'indirizzo navigator.credentials.get() non comporta la visualizzazione di alcuna UI, ma se l'utente imposta il campo di immissione annotato, tutte le passkey disponibili saranno incluse nelle opzioni di compilazione automatica. Se l'utente ne seleziona una, verrà sottoposta alla normale verifica di sblocco del dispositivo e solo allora la promessa restituita da .get() si risolverà con un risultato. Se l'utente non seleziona una passkey, la promessa non si risolve mai.

async function authenticate() {
  // ...

  const publicKeyCredentialRequestOptions = {
    // Server generated challenge:
    challenge: ****,
    // The same RP ID as used during registration:
    rpId: 'example.com',
    // You can omit `allowCredentials` as well:
    allowCredentials: []
  };

  const cred = await navigator.credentials.get({
    publicKey: publicKeyCredentialRequestOptions,
    signal: abortController.signal,
    // Specify 'conditional' to activate conditional UI
    mediation: 'conditional'
  });

  // This does not run until the user selects a passkey.
  const credential = {};
  credential.id = cred.id;
  credential.rawId = cred.id; // Pass a Base64URL encoded ID string.
  credential.type = cred.type;
  
  // ...
}
<input type="text" name="username" autocomplete="username webauthn" ...>

Puoi scoprire come creare questa esperienza utente nella pagina Accedere con una passkey tramite la compilazione automatica dei moduli e nel codelab Implementare le passkey con la compilazione automatica dei moduli in un'app web.

Riautenticazione

In alcuni casi, ad esempio quando si utilizzano le passkey per la riautenticazione, l'identificatore dell'utente è già noto. In questo caso, vorremmo utilizzare una passkey senza che il browser o il sistema operativo mostri alcun tipo di selettore di account. A tal fine, puoi passare un elenco di ID credenziali nel parametro allowCredentials.

In questo caso, se una delle credenziali indicate è disponibile localmente, all'utente viene richiesto immediatamente di sbloccare il dispositivo. In caso contrario, all'utente viene chiesto di presentare un altro dispositivo (uno smartphone o un token di sicurezza) contenente una credenziale valida.

Per ottenere questa esperienza utente, fornisci un elenco di ID credenziali per l'utente che esegue l'accesso. La parte soggetta a limitazioni dovrebbe essere in grado di interrogarli perché l'utente è già noto. Fornisci ID credenziali come oggetti PublicKeyCredentialDescriptor nella proprietà allowCredentials in navigator.credentials.get().

async function authenticate() {
  // ...

  const publicKeyCredentialRequestOptions = {
    // Server generated challenge:
    challenge: ****,
    // The same RP ID as used during registration:
    rpId: 'example.com',
    // Provide a list of PublicKeyCredentialDescriptors:
    allowCredentials: [{
      id: ****,
      type: 'public-key',
      transports: [
        'internal',
        'hybrid'
      ]
    }, {
      id: ****,
      type: 'public-key',
      transports: [
        'internal',
        'hybrid'
      ]
    }, ...]
  };

  const credential = await navigator.credentials.get({
    publicKey: publicKeyCredentialRequestOptions,
    signal: abortController.signal
  });

  // This does not run until the user selects a passkey.
  const credential = {};
  credential.id = cred.id;
  credential.rawId = cred.id; // Pass a Base64URL encoded ID string.
  credential.type = cred.type;
  
  // ...
}

Un oggetto PublicKeyCredentialDescriptor è costituito da:

  • id: un ID della credenziale di chiave pubblica che il RP ha ottenuto al momento della registrazione della passkey.
  • type: questo campo generalmente è 'public-key'.
  • transports: un suggerimento sui trasporti supportati dal dispositivo con questa credenziale, utilizzato dai browser per ottimizzare l'interfaccia utente che chiede all'utente di presentare un dispositivo esterno. Questo elenco, se fornito, deve contenere il risultato della chiamata a getTransports() durante la registrazione di ogni credenziale.

Riepilogo

Le credenziali rilevabili rendono l'esperienza di accesso tramite passkey molto più facile da usare consentendo loro di saltare l'inserimento di un nome utente. Con la combinazione di residentKey, requireResidentKey e allowCredentials, le parti soggette a limitazioni possono realizzare esperienze di accesso che:

  • Mostra un selettore di account modale.
  • Mostra la compilazione automatica di un modulo tramite passkey.
  • Riautenticazione.

Usa con oculatezza le credenziali rilevabili. In questo modo, puoi creare sofisticate esperienze di accesso tramite passkey che gli utenti troveranno senza problemi e con cui saranno più propensi a interagire.