Creazione condizionale della passkey (promozione post-accesso)

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() su AbortController collegato alla richiesta di compilazione automatica navigator.credentials.get() in attesa prima di chiamare navigator.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 opzioni navigator.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 excludeCredentials con 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), richiama PublicKeyCredential.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';