Approfondimento sulle credenziali rilevabili

Sebbene le credenziali FIDO, come le passkey, mirino a sostituire le password, la maggior parte di queste può anche evitare all'utente di dover digitare un nome utente. In questo modo, gli utenti possono autenticarsi selezionando un account da un elenco di passkey di cui dispongono per il sito web corrente.

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

Per assicurarti che le tue credenziali vengano create come passkey (credenziali rilevabili), specifica residentKey e requireResidentKey quando vengono create le credenziali.

Le relying party (RP) possono utilizzare le credenziali rilevabili omettendo allowCredentials durante l'autenticazione con passkey. In questi casi, il browser o il sistema mostrano 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 questo ID o l'ID credenziale restituito per cercare l'account anziché un nome utente digitato.

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

requireResidentKey e residentKey

Per creare una passkey, specifica authenticatorSelection.residentKey e authenticatorSelection.requireResidentKey su navigator.credentials.create() con i valori indicati di seguito.

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 RP preferisce creare una credenziale rilevabile, ma accetta una credenziale non rilevabile.
  • 'discouraged': la RP preferisce creare una credenziale non rilevabile, ma accetta una credenziale rilevabile.

requireResidentKey:

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

allowCredentials

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

Con le credenziali rilevabili, le RP possono mostrare un selettore di account modale per consentire all'utente di selezionare un account con cui accedere, seguito dalla verifica dell'utente. Questo è adatto per il flusso di autenticazione con passkey avviato premendo un pulsante dedicato all'autenticazione con 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 di un modulo per le 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, la finestra di dialogo modale viene comunque visualizzata e offre all'utente la possibilità di presentare una passkey da un altro dispositivo. Durante la transizione degli utenti alle passkey, potresti voler evitare questa UI per gli utenti che non ne hanno configurata una.

La selezione di una passkey potrebbe invece essere integrata nei prompt di compilazione automatica per i campi di un modulo di accesso tradizionale, insieme ai nomi utente e alle password salvati. In questo modo, un utente con passkey può "compilare" il modulo di accesso selezionando la propria passkey, gli utenti con coppie nome utente/password salvate possono selezionarle e gli utenti che non hanno nessuna delle due possono comunque digitare il proprio nome utente e la propria password.

Questa esperienza utente è ideale quando la RP è 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 a 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 a navigator.credentials.get() non mostrerà alcuna UI, ma se l'utente seleziona il campo di immissione annotato, le passkey disponibili verranno incluse nelle opzioni di compilazione automatica. Se l'utente ne seleziona uno, verrà eseguita la normale verifica dello sblocco del dispositivo e solo allora la promessa restituita da .get() verrà risolta con un risultato. Se l'utente non seleziona una passkey, la promessa non viene mai risolta.

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=&qu>ot;username webauthn" ...

Puoi scoprire come creare questa esperienza utente in Accedi con una passkey tramite la compilazione automatica dei moduli, nonché nel codelab Implementa 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 mostrino alcun tipo di selettore di account. A questo scopo, puoi passare un elenco di ID credenziali nel parametro allowCredentials.

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

Per ottenere questa esperienza utente, fornisci un elenco di ID credenziali per l'utente che esegue l'accesso. La RP dovrebbe essere in grado di eseguire query perché l'utente è già noto. Fornisci gli 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 della chiave pubblica ottenuta dalla RP al momento della registrazione della passkey.
  • type: questo campo è solitamente 'public-key'.
  • transports: un suggerimento dei trasporti supportati dal dispositivo che contiene questa credenziale, utilizzato dai browser per ottimizzare l'interfaccia utente che chiede all'utente di presentare un dispositivo esterno. Se fornito, questo elenco deve contenere il risultato della chiamata a getTransports() durante la registrazione di ogni credenziale.

Riepilogo

Le credenziali rilevabili rendono l'esperienza di accesso con passkey molto più facile da usare, consentendo agli utenti di saltare l'inserimento di un nome utente. Con la combinazione di residentKey, requireResidentKey e allowCredentials, le RP possono ottenere esperienze di accesso che:

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

Utilizza le credenziali rilevabili in modo strategico. In questo modo, puoi progettare esperienze di accesso con passkey sofisticate che gli utenti troveranno semplici e con cui saranno più propensi a interagire.