La guida per sviluppatori su WebAuthn e l'implementazione delle passkey. Scarica il cheat sheet in PDF o usa il sito per avere tutto in un unico posto.
Lukas R.
Creato: 6 marzo 2024
Aggiornato: 3 luglio 2026

Questa pagina è stata tradotta automaticamente. Leggi la versione originale in inglese qui.
Scarica l'intero Passkey Cheat Sheet gratuitamente e ottieni tutte le informazioni.
La guida definitiva per sviluppatori sulle passkey
Ottieni un riferimento per sviluppatori su tutto ciò che riguarda le passkey, che copre il supporto delle piattaforme, il comportamento dei browser, le best practice per l'UX e i suggerimenti per l'integrazione.

L'autenticazione con le passkey si basa su due processi, chiamati anche cerimonie, la registrazione (nota anche come fase di attestation) e l'accesso (noto anche come fase di assertion). Ogni fase richiede una sfida casuale generata dal server, che viene firmata dall'autenticatore e inviata al server WebAuthn per verificare l'utente.
Sperimenta i flussi passkey nel Passkeys Debugger.
La cerimonia di registrazione utilizza due oggetti centrali: PublicKeyCredentialCreationOptions e attestation.
La cerimonia di accesso utilizza due oggetti centrali: PublicKeyCredentialRequestOptions e assertion.
Scopri quante persone usano davvero le passkey.
Per la registrazione e l'accesso con le passkey, ci sono quattro oggetti principali:
Questa sezione spiega anche l'oggetto authenticatorSelection, che viene utilizzato in PublicKeyCredentialCreationOptions.
Igor Gjorgjioski
Head of Digital Channels & Platform Enablement, VicRoads
We hit 80% mobile passkey activation across 5M+ users without replacing our IDP.
See how VicRoads scaled passkeys to 5M+ users — alongside their existing IDP.
Read the case studyPublicKeyCredentialCreationOptions è l'oggetto centrale della fase di attestation (Registrazione). Viene creato e restituito dal server WebAuthn.
{ "PublicKeyCredentialCreationOptions": { "rp": { "id": "passkeys.eu", "name": "Corbado Passkeys Demo" }, "user": { "displayName": "john.doe", "id": "dXNyLZ….DU10Tc", "name": "john@doe.com" }, "challenge": "888fix4Bus...pHHr3Y", "pubKeyCredParams": [ { "alg": -7, "type": "public-key" }, { "alg": -257, "type": "public-key" } ], "excludeCredentials": [], "authenticatorSelection": { "authenticatorAttachment": "platform", "residentKey": "required", "userVerification": "required" }, "attestation": "none", "extensions": {} } }
L'oggetto contiene questi attributi:
Iscriviti al nostro Substack sulle passkey per le ultime novità.
PublicKeyCredentialRequestOptions è l'oggetto centrale della fase di assertion (Accesso). Viene creato e restituito dal server WebAuthn.
{ "publicKeyCredentialRequestOptions": { "challenge": "pT7HMA-…dFPHk", "timeout": 500, "rpId": "passkeys.eu", "userVerification": "preferred", "allowCredentials": [], "extensions": [] } }
L'oggetto contiene questi attributi:
Durante la Cerimonia di Attestation / Registrazione, l'Autenticatore restituisce questa Risposta di registrazione. Puoi provarlo tu stesso nel Passkeys Debugger.
{ "authenticatorAttachment": "platform", "id": "JKZbixUfKN_aZtimefYT-OjH5dw", "rawId": "JKZbixUfKN_aZtimefYT-OjH5dw", "response": { "attestationObject": { "fmt": "none", "attStmt": {}, "authData": { "rpIdHash": "PpZrl-Wqt-OFfBpyy2SraN1m7LT0GZORwGA7-6ujYkM", "flags": { "userPresent": true, "userVerified": true, "backupEligible": true, "backupStatus": true, "attestedData": true, "extensionData": false }, "counter": 0, "aaguid": { "raw": "fbfc3007-154e-4ecc-8c0b-6e020557d7bd", "name": "iCloud Keychain" }, "credentialID": "JKZbixUfKN_aZtimefYT-OjH5dw", "credentialPublicKey": "pQECAyYgASFYIPWLalDzyxIDmAADvfK8iNM5To50kh7TyPH-teEz8RMdIlgg3D7bPIWQJ8z-WFn3zdYZzJw9c7mhPdmflQqD9vV7efA", "parsedCredentialPublicKey": { "keyType": "EC2 (2)", "algorithm": "ES256 (-7)", "curve": 1, "x": "9YtqUPPLEgOYAAO98ryI0zlOjnSSHtPI8f614TPxEx0", "y": "3D7bPIWQJ8z-WFn3zdYZzJw9c7mhPdmflQqD9vV7efA" } } }, "clientDataJSON": { "type": "webauthn.create", "challenge": "k2p6f-upzP_hc6NZvmMAxiI0VSTeQIeXXVRGW62LTj0", "origin": "https://www.passkeys-debugger.io", "crossOrigin": false }, "transports": ["hybrid", "internal"], "authenticatorData": "PpZrl-Wqt-OFfBpyy2SraN1m7LT0GZORwGA7-6ujYkNdAAAAAPv8MAcVTk7MjAtuAgVX170AFCSmW4sVHyjf2mbYpnn2E_jox-XcpQECAyYgASFYIPWLalDzyxIDmAADvfK8iNM5To50kh7TyPH-teEz8RMdIlgg3D7bPIWQJ8z-WFn3zdYZzJw9c7mhPdmflQqD9vV7efA", "publicKey": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE9YtqUPPLEgOYAAO98ryI0zlOjnSSHtPI8f614TPxEx3cPts8hZAnzP5YWffN1hnMnD1zuaE92Z-VCoP29Xt58A", "publicKeyAlgorithm": -7 }, "type": "public-key", "clientExtensionResults": {} }
L'attestation contiene alcuni componenti importanti come attestationObject, algorithm e i flag di transport.
Tratto dalle Specifiche WebAuthn del W3C
L'attestationObject è un oggetto codificato in CBOR che contiene informazioni sulle credenziali appena create, la chiave pubblica e altri dati rilevanti:
Scopri di più sulle estensioni.
Le passkey vengono generate con algoritmi COSE, indicando l'algoritmo utilizzato nell'attributo algorithm di parsedCredentialPublicKey nell'oggetto attestation. Ecco una panoramica dei più rilevanti algoritmi COSE:
La proprietà transports indica i meccanismi attraverso i quali un autenticatore può comunicare con un client. Alcune combinazioni di valori di esempio comuni sono:
Durante la Cerimonia di Assertion / Accesso, l'Autenticatore restituisce questa Risposta di accesso. Puoi provarlo tu stesso nel Passkeys Debugger.
{ "id": "JKZbixUfKN_aZtimefYT-OjH5dw", "rawId": "JKZbixUfKN_aZtimefYT-OjH5dw", "type": "public-key", "authenticatorAttachment": "platform", "response": { "authenticatorData": { "rpIdHash": "PpZrl-Wqt-OFfBpyy2SraN1m7LT0GZORwGA7-6ujYkM", "flags": { "userPresent": true, "userVerified": true, "backupEligible": true, "backupStatus": true, "attestedData": false, "extensionData": false }, "counter": 0 }, "clientDataJSON": { "type": "webauthn.get", "challenge": "GCVkITWbe2l2dttsn_DgJYvH9QPHPDo0ygWgcgI6B7U", "origin": "https://www.passkeys-debugger.io", "crossOrigin": false, "other_keys_can_be_added_here": "do not compare clientDataJSON against a template. See https://goo.gl/yabPex" }, "signature": "MEQCIA-orC8N2KKWOxyY17BWP8lB-Be5to9btXRnJZf2SLhXAiBGxJe5Eu5LwOTbsyzAYmIXHOhlC3pN7s7Q1fRLvEW57g", "userHandle": "_FKz1uwqmR_3yGq6hJntzoIFwFC_d1u_53YRELh0KlE" } }
L'assertion contiene alcuni componenti importanti come flag, signature e userHandle.
Ecco una panoramica dei flag più rilevanti e delle loro combinazioni:
La signature (firma) viene utilizzata per verificare che l'utente che cerca di accedere abbia effettivamente la chiave privata. La firma viene creata concatenando authenticatorData e clientDataHash (ovvero la versione SHA-256 di ClientDataJSON) e firmando il risultato con la chiave privata (nell'autenticatore). Per verificare con la chiave pubblica, concateniamo anch'essi authenticatorData e clientDataHash. Se il risultato della verifica restituisce true, l'autenticazione ha successo.
L'userHandle è l'effettivo user_id. Scopri di più su user_id nella sezione 4.1 Schema del database.
L'oggetto authenticatorSelection consente al server di dettare le impostazioni per l'autenticatore e la creazione delle credenziali con i seguenti valori:
Chiavi residenti (chiamate anche Credenziali rilevabili - Discoverable Credential): Le chiavi residenti sono memorizzate sull'autenticatore e recuperate durante l'autenticazione. In questo modo il client può scoprire un elenco di chiavi possibili, motivo per cui la Conditional UI richiede chiavi residenti. Chiavi non residenti (chiamate anche Credenziali non rilevabili - Non-Discoverable Credential): In caso di chiavi non residenti, l'ID della credenziale è memorizzato sul server e fornito durante l'autenticazione. L'ID della credenziale è un identificatore opaco la cui struttura interna è specifica dell'implementazione: gli autenticatori possono memorizzare le chiavi private direttamente, utilizzare il wrapping delle chiavi crittografate o derivare le chiavi da segreti interni. Il meccanismo esatto varia a seconda dell'implementazione dell'autenticatore.
Attenzione: Se impostato su "Preferred", l'utente o il suo dispositivo possono saltare la verifica dell'utente nel processo di autenticazione (scopri di più in questo articolo).
La Conditional UI (autofill delle passkey) mostra le passkey disponibili in un menu a tendina di selezione per l'utente, quando un utente ha una chiave residente registrata con il relying party. Migliora l'usabilità delle passkey, ma richiede sforzi di sviluppo aggiuntivi e non è disponibile per tutte le combinazioni di sistemi operativi e browser.
Come un normale accesso, anche la Conditional UI utilizza gli oggetti PublicKeyCredentialRequestOptions e assertion.
La Conditional UI non è ancora disponibile su tutte le combinazioni di sistemi operativi e browser. Ecco una panoramica dell'attuale copertura dei browser (marzo 2024):
Per una panoramica aggiornata vedi questo sito.
Un codice completo e minimalista per un metodo di Conditional UI si presenta così:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Conditional UI</title> </head> <body> <input type="text" id="username" autocomplete="username webauthn" /> <script> async function passkeyLogin() { try { // recupera le opzioni della richiesta (incluso il challenge) dal server WebAuthn let options = await WebAuthnClient.getPublicKeyRequestOptions(); const credential = await navigator.credentials.get({ publicKey: options.publicKeyCredentialRequestOptions, mediation: "conditional", }); const userData = await WebAuthnClient.sendSignedChallenge(credential); window.location.href = "/logged-in"; } catch (error) { console.log(error); } } passkeyLogin(); </script> </body> </html>
La Conditional UI funziona solo con le chiavi residenti / credenziali rilevabili. Si raccomanda di fornire un endpoint server diverso per avviare l'accesso tramite Conditional UI. Il client deve soddisfare diversi requisiti:
Per evitare errori, il server dovrebbe prima testare la disponibilità del client con questa funzione:
Nel traffico reale, i problemi di rilevamento e del ciclo di vita emergono spesso come NotAllowedError o AbortError. Usa questa guida agli errori WebAuthn per la classificazione tra previsto e imprevisto, inclusi gli errori passkey del Credential Manager nativo.
// source: https://developer.mozilla.org/en-US/docs/Web/API/PublicKeyCredential/isConditionalMediationAvailable#examples // Availability of `window.PublicKeyCredential` means WebAuthn is usable. if (window.PublicKeyCredential && PublicKeyCredential.isConditionalMediationAvailable) { // Check if conditional mediation is available. const isCMA = await PublicKeyCredential.isConditionalMediationAvailable(); if (isCMA) { // Call WebAuthn authentication start endpoint let options = await WebAuthnClient.getPublicKeyRequestOptions(); const credential = await navigator.credentials.get({ publicKey: options.publicKeyCredentialRequestOptions, mediation: "conditional", }); /* ... */ } }
Il campo di input dovrebbe ricevere un token autofill HTML, che segnala al client di popolare le passkey per la richiesta in corso. Oltre alle passkey, i token autofill possono essere abbinati a token esistenti, ad esempio nomi utente e password:
<label for="name">Nome utente:</label> <input type="text" name="name" autocomplete="username webauthn" /> <label for="password">Password:</label> <input type="password" name="password" autocomplete="current-password webauthn" />
Non esiste uno schema di database obbligatorio o standardizzato per i server WebAuthn. Tuttavia, questo esempio di schema di database può essere utilizzato per memorizzare le informazioni richieste e fornire tutte le funzionalità di un server WebAuthn:
Gli attributi in grassetto sono obbligatori per un'implementazione minima funzionante, mentre gli altri sono necessari solo per funzionalità opzionali, ma utili.
Nome visualizzato dell'utente (user.displayName): Nome leggibile e facile da usare per l'utente che è tipicamente il nome completo dell'utente. Viene mostrato all'utente, ma non utilizzato durante l'autenticazione.
Nome Utente (user.name): Nome univoco e leggibile che è tipicamente un indirizzo e-mail o un nome utente. Può essere mostrato all'utente, ma non è utilizzato durante l'autenticazione.
L'ID del Relying Party (rpID) è un dominio memorizzato all'interno della passkey, garantendo che la passkey funzioni solo per il dominio corretto (URL del browser, vedi questo articolo per le app native). Durante l'autenticazione, l'rpID viene confrontato con l'URL del browser ed è consentito solo in questi due casi:
Ecco alcuni esempi di combinazioni consentite (e non):
Ecco un elenco di strumenti e siti web utili per l'implementazione delle passkey.
chrome://device-log)Per le strategie su come ottimizzare la UX delle passkey oltre l'implementazione tecnica, consulta le nostre guide sulle best practice per la creazione di passkey e le best practice per l'accesso con passkey.
Se desideri implementare le passkey con poche righe di codice in qualsiasi applicazione, puoi anche utilizzare Corbado Complete (per le nuove app) o Corbado Connect (per le app esistenti).
Corbado è la Authentication Intelligence Platform per i team CIAM che gestiscono l'autenticazione consumer su larga scala. Ti aiutiamo a vedere ciò che i log IDP e gli strumenti di analytics generici non mostrano: quali dispositivi, versioni di OS, browser e gestori di credenziali supportano i passkey, perché gli enrollment non si trasformano in login, dove il flusso WebAuthn fallisce e quando un aggiornamento di OS o browser interrompe silenziosamente il login — tutto senza sostituire Okta, Auth0, Ping, Cognito o il tuo IDP interno. Due prodotti: Corbado Observe aggiunge osservabilità per i passkey e qualsiasi altro metodo di login. Corbado Connect introduce passkey gestiti con analytics integrato (insieme al tuo IDP). VicRoads gestisce i passkey per oltre 5M di utenti con Corbado (+80 % di attivazione passkey). Parla con un esperto di Passkey →
La Conditional UI richiede la verifica del supporto del browser tramite PublicKeyCredential.isConditionalMediationAvailable() prima di avviare l'autenticazione. Il campo di input deve includere il token HTML autocomplete="username webauthn" e l'utente deve avere registrato una chiave residente (credenziale rilevabile). Si raccomanda un endpoint server separato per gestire il flusso di accesso della Conditional UI.
Come minimo, memorizza l'ID della Credenziale, generato dall'autenticatore durante la registrazione, e l'ID Utente (user_id), che viene restituito come userHandle nell'oggetto assertion. Utilizza l'ID della Credenziale per cercare l'account utente associato e confronta l'userHandle per convalidare l'autenticazione. Evita di usare user.name per il confronto poiché può cambiare nel tempo.
Le chiavi residenti (credenziali rilevabili) sono memorizzate sull'autenticatore stesso e recuperate durante l'autenticazione, il che è necessario affinché la Conditional UI funzioni. Le chiavi non residenti memorizzano l'ID della credenziale sul server e lo inviano all'autenticatore durante l'autenticazione. Il campo residentKey in authenticatorSelection controlla questo comportamento con valori "required", "preferred" o "discouraged".
Il campo userVerification controlla se l'autenticatore deve verificare l'utente durante l'accesso, accettando valori "required", "preferred" (impostazione predefinita) o "discouraged". Quando è impostato su "preferred", l'utente o il suo dispositivo possono saltare del tutto la verifica durante il processo di autenticazione, indebolendo potenzialmente la sicurezza. Impostarlo su "required" assicura che la verifica avvenga sempre prima del completamento dell'autenticazione.
Scopri come Corbado si integra con la tua distribuzione di passkey e con lo stack di autenticazione esistente.
Esplora la Console
Articoli correlati
Indice