Sebbene le credenziali FIDO, come le passkey, mirino a sostituire le password, la maggior parte di queste può anche evitare all'utente di digitare un nome utente. In questo modo, gli utenti possono autenticarsi selezionando un account da un elenco di passkey che hanno 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 era necessario inserire 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 credenziali vengano create come passkey (credenziali rilevabili), specifica residentKey e requireResidentKey quando viene creata la credenziale.
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 una, il valore user.id verrà incluso nella firma risultante. Il server può quindi utilizzare questo valore 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': deve essere creata una credenziale rilevabile. Se non è possibile crearla, viene restituitoNotSupportedError.'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 questa proprietà su
trueseresidentKeyè'required', altrimenti impostala sufalse.
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:
- Mostra un selettore account modale
- Mostra la compilazione automatica del modulo della passkey
- Riautenticazione
Mostra un selettore account modale
Con le credenziali rilevabili, le RP possono mostrare un selettore account modale in modo che l'utente possa selezionare un account con cui accedere, seguito dalla verifica dell'utente. Questa opzione è adatta 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 del modulo della passkey
Il selettore account modale descritto sopra funziona bene se la maggior parte degli utenti utilizza le passkey e le ha disponibili sul dispositivo locale. Per un utente che non ha passkey locali, viene comunque visualizzata la finestra di dialogo modale che gli offre 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.
In alternativa, la selezione di una passkey può 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 le passkey può "compilare" il modulo di accesso selezionando la propria passkey, gli utenti con coppie nome utente/password salvate possono selezionarle e gli utenti senza nessuna delle due possono comunque digitare il nome utente e la 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 username HTML con autocomplete="username webauthn" o un campo di immissione password con autocomplete="password webauthn".
La chiamata a navigator.credentials.get() non comporta la visualizzazione di alcuna UI, ma se l'utente mette a fuoco il campo di immissione annotato, tutte le passkey disponibili verranno incluse nelle opzioni di compilazione automatica. Se l'utente ne seleziona una, verrà eseguita la normale verifica di 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="username webauthn" ...>
Puoi scoprire come creare questa esperienza utente in Accedere con una passkey tramite la compilazione automatica dei moduli, nonché 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 account. Per farlo, puoi passare un elenco di ID credenziali nel parametro allowCredentials.
In questo caso, se una delle credenziali denominate è disponibile localmente, all'utente viene immediatamente richiesto lo sblocco del dispositivo. In caso contrario, all'utente viene chiesto di presentare un altro dispositivo (uno smartphone o un token di sicurezza) che contenga 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 eseguirne una 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 è composto da:
id: un ID della credenziale della chiave pubblica che la RP ha ottenuto durante la registrazione della passkey.type: questo campo è in genere'public-key'.transports: un suggerimento sui trasporti supportati dal dispositivo che contiene questa credenziale, utilizzato dai browser per ottimizzare l'UI che chiede all'utente di presentare un dispositivo esterno. Questo elenco, se fornito, deve contenere il risultato della chiamata agetTransports()durante la registrazione di ogni credenziale.
Riepilogo
Le credenziali rilevabili rendono l'esperienza di accesso con passkey molto più semplice per l'utente, consentendogli di saltare l'inserimento di un nome utente. Con la combinazione di residentKey, requireResidentKey e allowCredentials, le RP possono ottenere esperienze di accesso che:
- Mostrano un selettore account modale.
- Mostrano la compilazione automatica del modulo della 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 è più probabile che interagiscano.