Questa guida spiega in dettaglio come registrare automaticamente e in modo silenzioso una passkey per un utente subito dopo un accesso riuscito basato su password, riducendo al minimo gli attriti e aumentando l'adozione delle passkey.
Il momento giusto per l'attivazione
La creazione automatica delle passkey (nota anche come creazione condizionale o promozione silenziosa post-accesso) DEVE essere attivata solo immediatamente dopo un accesso completo e riuscito che ha richiesto una password.
- Non tentare la creazione condizionale per i flussi senza password (ad es. link magici, OTP via SMS o federazione delle identità).
- Se è richiesta l'autenticazione a più fattori, DEVI attendere che tutti i fattori siano stati verificati prima di avviare la creazione condizionale.
- Assicurati che sia attiva una sessione utente valida e autenticata prima di effettuare richieste agli endpoint di creazione.
Procedura di implementazione
1. Interrompi le azioni di compilazione automatica precedenti
Se la pagina di accesso utilizza la compilazione automatica dei moduli (UI condizionale/Get), la chiamata get della credenziale attiva deve essere interrotta per evitare conflitti del browser.
- Chiama
abortController.abort()suAbortControllercollegato alla richiesta di compilazione automaticanavigator.credentials.get()in attesa prima di chiamarenavigator.credentials.create().
2. Rilevamento delle caratteristiche
Determina se la creazione condizionale è disponibile controllando conditionalCreate con PublicKeyCredential.getClientCapabilities().
const capabilities = await PublicKeyCredential.getClientCapabilities();
if (capabilities.conditionalCreate) {
// Conditional create is available
}
3. Crea una passkey con la creazione condizionale
- Passa
mediation: 'conditional'all'interno delle opzioninavigator.credentials.create(). In questo modo, il browser gestisce il flusso di creazione della passkey in background o in modo contestuale senza mostrare finestre di dialogo modali invasive. - Compila
excludeCredentialscon gli ID delle credenziali delle passkey esistenti dell'utente per evitare di registrare chiavi duplicate.
4. Gestione degli errori silenziosa
- Inserisci il prompt di creazione della passkey (
navigator.credentials.create) in un blocco try/catch. DEVI intercettare e ignorare silenziosamente le tipiche eccezioni rivolte agli utenti (InvalidStateError,NotAllowedError,AbortError) senza mostrare all'utente alcuna UI di errore.
5. Verifica della presenza dell'utente lato server
- L'endpoint di verifica lato server DEVE allentare il requisito di presenza dell'utente (UP) (
requireUserPresence: false) SOLO durante la verifica delle credenziali prodotte da un trigger di creazione condizionale. La verifica della presenza rigorosa deve rimanere attiva per le creazioni esplicite standard.
6. Gestisci correttamente la verifica del server non riuscita
- Se
navigator.credentials.create()ha esito positivo, ma il recupero della verifica del server restituisce una risposta errata (ad es. la verifica della firma non va a buon fine), richiamaPublicKeyCredential.signalUnknownCredential()per evitare che le credenziali orfane rimangano nel provider di passkey.
Esempio di codice
// optionsFetch and registerVerifyFetch are app-defined server endpoint requests
import { optionsFetch, registerVerifyFetch } from './api.js';
async function triggerConditionalCreate(loginAbortController) {
const capabilities = await PublicKeyCredential.getClientCapabilities();
if (capabilities.conditionalCreate !== true) {
return; // Platform does not support conditional creation
}
// 1. Abort any active autofill conditional-get controllers to clear the WebAuthn pipeline
loginAbortController.abort();
// 2. Fetch creation options signaling the backend that this is a conditional request
const creationOptionsJSON = await optionsFetch({ conditional: true });
const publicKey = PublicKeyCredential.parseCreationOptionsFromJSON(creationOptionsJSON);
let credential;
try {
// 3. Invoke silent credentials creation prompt
credential = await navigator.credentials.create({
publicKey,
mediation: 'conditional' // Silent background creation mediation
});
} catch (e) {
// 4. Silently swallow common WebAuthn browser exceptions
if (['InvalidStateError', 'NotAllowedError', 'AbortError'].includes(e.name)) {
return;
}
console.error('Unexpected conditional create error:', e);
return;
}
// 5. Server verification step using dedicated Try/Catch block
let encodedResponse = credential.toJSON();
try {
const response = await registerVerifyFetch(encodedResponse);
if (!response.ok) {
// If the server verification fails, clean up using Signal API
if (PublicKeyCredential.signalUnknownCredential) {
await PublicKeyCredential.signalUnknownCredential({
rpId, // RP ID must match the one defined on the server
credentialId: encodedResponse.id
});
}
}
} catch (serverErr) {
console.error('Verification network failure:', serverErr);
if (PublicKeyCredential.signalUnknownCredential) {
await PublicKeyCredential.signalUnknownCredential({
rpId, // RP ID must match the one defined on the server
credentialId: encodedResponse.id
});
}
}
}
Strategie di fallback
Fallback del rilevamento delle funzionalità delle passkey
Installa sempre "webauthn-polyfills" e importalo nel contesto.
Tieni presente che, se PublicKeyCredential è supportato, lo è anche PublicKeyCredential.getClientCapabilities.
import 'webauthn-polyfills';
Sincronizzazione di riserva dell'API Signal
L'API WebAuthn Signal (webauthn-signals) è un'ottimizzazione progressiva utilizzata per mantenere i gestori delle password sincronizzati con lo stato delle credenziali del server.
- Esperienza di riserva: limitata tramite
if (PublicKeyCredential.signalUnknownCredential). Se non è supportata, la sincronizzazione della verifica in background viene ignorata correttamente senza generare eccezioni del browser.
Easy JSON Serialization Fallback
Installa sempre "webauthn-polyfills" e importalo nel contesto.
Tieni presente che, se PublicKeyCredential è supportato, lo sono anche PublicKeyCredential.parseCreationOptionsFromJSON e PublicKeyCredential.prototype.toJSON.
import 'webauthn-polyfills';