Questa pagina è stata tradotta automaticamente. Leggi la versione originale in inglese qui.
In produzione, gli errori WebAuthn sono fonte di confusione
perché i browser espongono un set ridotto di nomi DOMException (come NotAllowedError) che
possono rappresentare molteplici cause di fondo. Oltre a ciò, la stragrande maggioranza degli "errori" -
spesso superiore al 95% nelle implementazioni
su larga scala ottimizzate - rappresenta in realtà
un comportamento previsto (l'utente ha interrotto la richiesta passkey del sistema operativo).
Sperimenta i flussi passkey nel Passkeys Debugger.
Importante: per motivi di privacy, i browser non distinguono se l'utente ha annullato attivamente l'operazione o se non esisteva alcuna passkey. Tuttavia, in alcune situazioni e con abbastanza contesto, sia sul web che sulle piattaforme native, alcuni di questi casi possono essere differenziati utilizzando segnali come le tempistiche.
Se desideri le definizioni canoniche per questi nomi, inizia da
MDN DOMException. Per
le condizioni specifiche di WebAuthn che portano a queste eccezioni (e che i browser sono tenuti
a far rispettare), consulta la Specifica W3C Web Authentication.
Se tratti tutti gli errori come "bug", farai le cose sbagliate:
NotAllowedErrorIn questo articolo rispondiamo a:
NotAllowedError in bucket azionabili (annullamento vs timeout vs
disponibilità)?NotAllowedError è un segnale di superficie, non una causa principale. Può significare annullamento,
timeout, "nessuna credenziale locale" o attivazione utente mancante a seconda del contesto.NotAllowedError significa cose
diverse durante il login con Conditional UI, il login modale, la creazione manuale di passkey, la creazione condizionale
e le aggiunte attivate automaticamente.<1s),
annullamento dell'utente (1-15s) e timeout (30s+) sono categorie fondamentalmente diverse.AbortError è solitamente un problema di ciclo di vita/concorrenza (navigazione, re-render, richieste
multiple in corso).SecurityError è quasi sempre legato a configurazione/contesto ed è raro nelle implementazioni di produzione
mature.error.name in modo da poter classificare gli errori in bucket che puoi
effettivamente correggere.Se hai solo bisogno di una mappatura rapida per sbloccare il debugging, inizia con questa tabella. È sbilanciata verso ciò che i team vedono effettivamente nelle dashboard e nei ticket di supporto.
error.name | Cosa significa di solito in produzione | Cosa controllare per confermare | Prima azione (UX + ingegneria) |
|---|---|---|---|
NotAllowedError | Foglio ignorato dall'utente, timeout o mancata disponibilità raggruppati in un unico bucket. Questo è il bucket di errori più grande in produzione. | time-to-error, se è apparsa l'interfaccia utente QR/ibrida, se la cerimonia è iniziata da un'azione utente reale | Tratta come previsto: ripristina UI + mostra fallback |
AbortError | La tua app (o il browser) ha interrotto la cerimonia | navigazione/re-render durante la cerimonia; chiamate WebAuthn concorrenti; AbortController.abort() | Imponi una sola richiesta in corso; impedisci cambi di route; gestisci l'interruzione come normale flusso di controllo |
SecurityError | Contesto/policy non consentito | origine + strategia RP ID; iframe/embedding; HTTPS; feature policy | Correggi configurazione RP ID/origine; convalida le policy di embedding; assicurati che il contesto sia sicuro |
InvalidStateError | Mancata corrispondenza dello stato (spesso registrazione duplicata) | registrazione vs login; excludeCredentials; credenziale esistente sull'autenticatore | Tratta come "già registrato"; adatta il percorso UX; correggi la generazione delle opzioni |
ConstraintError | I requisiti non possono essere soddisfatti | authenticatorAttachment, userVerification, requisiti delle resident key | Rilassa i vincoli o fornisci un percorso/fallback alternativo. Esempio: blocco schermo mancante su Android |
DataError | Gli input sono malformati/incoerenti | codifica base64url; formati di id/challenge/user handle | Correggi codifica/serializzazione; aggiungi convalida nella generazione delle opzioni |
NotSupportedError | La piattaforma/il browser non supporta ciò che hai richiesto | versione di OS/browser; presupposti del rilevamento delle funzionalità | Applica subito un fallback; registra il segmento; evita di mostrare CTA per passkey in ambienti non supportati |
UnknownError | Piattaforma/autenticatore non riuscito in modo generico | picchi dopo aggiornamenti OS; build del dispositivo; problemi del provider del credential manager | UX compatibile con i tentativi (retry); acquisisci numeri di build; indaga sui picchi del segmento |
Una cosa facile da trascurare: lo stesso error.name può significare cose molto diverse
a seconda del tipo di operazione. Tieni presente il contesto dell'operazione mentre leggi le
sezioni seguenti. In pratica, gli errori di creazione di passkey
(registrazione) superano in genere di gran lunga gli errori di login: la tabella precedente
si applica a entrambi, ma la creazione è dove risiede la maggior parte del volume.
Successivamente, approfondiremo NotAllowedError perché è quello che vedrai di più e
quello che i team fraintendono più spesso.
NotAllowedError spesso sembra che "le passkey abbiano fallito", ma di solito è la piattaforma
che ti dice che l'utente non ha completato l'interfaccia utente del sistema operativo. La chiave è suddividerlo in bucket su cui puoi
agire.
Cosa vedrai nella console del browser:
| Origine | Messaggio di errore |
|---|---|
| Chrome, Edge | NotAllowedError: The operation either timed out or was not allowed. See: https://www.w3.org/TR/webauthn-2/#sctn-privacy-considerations-client. |
| Safari, WebKit | NotAllowedError: The request is not allowed by the user agent or the platform in the current context, possibly because the user denied permission. |
| Safari, WebKit | NotAllowedError: This request has been cancelled by the user. |
| Chrome, Edge | NotAllowedError: The operation is not allowed at this time because the page does not have focus. |
| Safari, WebKit | NotAllowedError: The document is not focused. |
| Firefox | NotAllowedError: Operation failed. |
Tutti questi emergono come error.name === "NotAllowedError". Il error.message differisce in base
al motore del browser e alla causa sottostante, ma il risultato è lo stesso: la cerimonia non
è stata completata.
Ciò si applica sia al login che alla creazione della passkey. Durante il login (Conditional UI, modale
con o senza allowList), NotAllowedError in genere significa che l'utente non ha completato la
cerimonia. Durante la creazione della passkey, lo stesso errore
emerge per motivi diversi: l'utente ha chiuso la finestra di dialogo di creazione (la creazione condizionale
non ha funzionato, o la pagina ha perso il focus durante un'aggiunta attivata automaticamente. Il tipo di operazione
cambia il significato dell'errore e cosa dovresti fare al riguardo.
Le tempistiche sono spesso un segnale sottovalutato. Un errore dopo meno di un secondo da un clic di solito è un rifiuto immediato (l'ambiente non può farlo, il documento non è focalizzato, manca la capacità). Un errore dopo pochi secondi è un annullamento dell'utente (ha visto la finestra di dialogo e ha deciso di non procedere). Un errore dopo oltre 30 secondi è un timeout. Sulle piattaforme native, le tempistiche sono particolarmente importanti: i round-trip dell'autenticatore, i prompt biometrici e gli handoff del credential manager hanno tutti durate caratteristiche che ti aiutano a separare "non ha funzionato" da "l'utente si è allontanato". Non riesci ancora a distinguere facilmente se esisteva una passkey.
Non hai bisogno di un segnale perfetto. Hai bisogno di un contesto sufficiente per evitare di trattare ogni
NotAllowedError allo stesso modo. iOS/Safari riceve
un'attenzione specifica di seguito perché ha vincoli unici (requisiti di attivazione dell'utente
nelle versioni precedenti), ma nel volume di errori puro, Windows e i browser Chromium spesso
generano più NotAllowedError di qualsiasi altra piattaforma. Questi segnali ti portano spesso all'80%
del risultato:
| Segnale | Significato probabile | Cosa fare dopo |
|---|---|---|
Errore immediato (<1s) | Rifiuto dell'ambiente: nessuna capacità, documento non focalizzato, superficie di creazione condizionale non disponibile | Controlla il rilevamento delle funzionalità; assicurati che il documento sia in primo piano; verifica che l'operazione sia supportata su questa piattaforma |
| Annullamento rapido (1-3s) | Prompt a sorpresa / nessun contesto | Cambia la tempistica del prompt; aggiungi un tempo di ricarica (cooldown) dopo l'annullamento |
| Annullamento con tempistiche dell'utente (3-15s) | L'utente ha visto la finestra di dialogo e ha scelto di non procedere | UX prevista; ripristina UI + mostra fallback |
| Timeout (30s+) | La cerimonia è andata in timeout senza l'intervento dell'utente | Inserisci nel bucket "non completato"; valuta se il prompt sia stato notato |
| Appare UI QR/ibrida prima del fallimento | Nessuna credenziale locale disponibile su questo dispositivo. Nota: rilevare in modo affidabile le decisioni del codice QR prima che si verifichino richiede un livello di passkey intelligence che sappia se esiste una credenziale utilizzabile sul dispositivo attuale. | Limita le offerte di passkey; rendi esplicito "Usa telefono"; riduci le sorprese con i QR |
| Concentrato su iOS/Safari e attivato senza un clic/tocco | Attivazione utente mancante | Avvia la cerimonia da un vero gesto dell'utente |
| Durante conditional create o aggiunta attivata automaticamente | Autofill non disponibile, credenziale già esistente o pagina che ha perso il focus. Gli errori di conditional create possono apparire all'improvviso e ad alto volume quando la funzione viene lanciata, rendendo questa una delle fonti di errore più grandi durante la notte. | Vedi conditional create; controlla lo stato di visibilità del documento; usa getClientCapabilities() per verificare il supporto a conditionalCreate prima di tentare la chiamata |
Questo è anche il motivo per cui NotAllowedError dovrebbe essere raramente visibile all'utente. Non è un messaggio su cui
l'utente può agire.
La classificazione del contesto è anche il punto in cui i tassi di successo si dividono più nettamente. L'
Analisi del tasso di successo dell'autenticazione tramite passkey del Corbado Passkey Benchmark 2026
misura il completamento del primo trimestre 2026 al 55-95% per i flussi identifier-first su dispositivi sconosciuti rispetto
al 95-99% per i ritorni su dispositivi noti in tutte le
implementazioni B2C su larga scala.
L'identifier-first web su iOS raggiunge un completamento dell'85-95%
(% CDA 0–5%), web su Android al 70–85% (% CDA 5–10%) e web su macOS al 70–85% (% CDA 10–15%),
mentre il web su Windows si attesta al 45-60% di completamento identifier-first con % CDA al 55-65% su
Windows 11 e 40-55% su Windows 10. Leggere
il volume di NotAllowedError senza separare i contesti di dispositivi noti rispetto a quelli sconosciuti confonde
due regimi di successo fondamentalmente diversi.
Una sfumatura che conta in produzione: alcuni user agent potrebbero mostrare i timeout come
TimeoutError, ma molti team vedono ancora i timeout raggruppati in NotAllowedError nelle
dashboard. In ogni caso, tratta i timeout come "la cerimonia non è stata completata" e classificali usando
tempistiche e contesto.
Quando il foglio del sistema operativo viene ignorato o va in timeout, l'interfaccia utente dovrebbe riprendersi immediatamente e reagire in modo aggraziato. Un insieme pratico di regole:
Oltre le basi:
Se i tuoi "annullamenti" sono veramente alti, il passo successivo è correggere le cause principali alla loro base: tempistiche del prompt, sorprese sui codici QR e bassa disponibilità.
Inizia con le modifiche che spostano rapidamente le metriche:
NotAllowedError. Inizia con
isUVPAA() come controllo più
basilare, quindi usa getClientCapabilities() per
controlli più precisi (creazione condizionale, get condizionale, trasporto ibrido,
autenticatore di piattaforma). Tieni presente che le
API di rilevamento possono interrompersi con gli aggiornamenti del sistema operativo: iOS 26.2 includeva un bug WebKit
in cui isUVPAA() restituiva false su tutti i browser basati su WKWebView
anche se le passkey funzionavano correttamente, causando improvvisi picchi di NotAllowedError per
il 10-25% degli utenti iOS.I nomi degli errori sono un bersaglio mobile. Ci sono proposte in corso per aggiungere errori WebAuthn più granulari (ad esempio, per separare "nessuna credenziale disponibile" da "l'utente ha annullato"). A partire da febbraio 2026, ciò non è implementato in nessun browser, quindi vale ancora la pena creare i propri bucket di motivazioni in base al contesto e alle tempistiche. Se desideri seguire questo lavoro, vedi WebAuthn issue #2062 e l' Spiegazione dei nuovi codici di errore.
I restanti nomi degli errori sono meno frequenti ma vale comunque la pena capirli quando appaiono.
AbortError è raro in volume rispetto a NotAllowedError, ma quando appare è
altamente diagnostico: di solito significa che la cerimonia non è terminata perché la tua app
ha invalidato la richiesta (si è verificata una navigazione, lo stato è cambiato o è iniziata una seconda richiesta).
Cosa vedrai nella console del browser:
| Origine | Messaggio di errore |
|---|---|
| Chrome, Edge | AbortError: The operation was aborted. |
| Chrome, Edge | AbortError: Aborted by AbortSignal. |
| Firefox | AbortError: signal is aborted without reason |
| Firefox | AbortError: Operation timed out. |
| Safari, WebKit | AbortError: The user aborted a request. |
| Chrome | AbortError: CredentialContainer request is not allowed. |
Le cause comuni di produzione includono:
AbortController.abort() durante tentativi o pulizia dello statoPer risolverlo, concentrati sul rendere la cerimonia una "sezione critica":
Se noti AbortError concentrato in superfici integrate o app multi-dominio, il bucket successivo
da controllare è SecurityError.
SecurityError è il browser che ti dice: "questo contesto non è autorizzato a fare ciò che hai
chiesto." In pratica è quasi sempre configurazione, non comportamento dell'utente. In implementazioni
di produzione mature, SecurityError è raro perché questi problemi vengono in genere individuati
durante i test di integrazione. Se compare in produzione, di solito significa che un nuovo dominio,
contesto di integrazione o target di distribuzione è stato aggiunto senza un'adeguata configurazione WebAuthn.
Le cause più comuni includono:
.well-known/webauthn o .well-known/assetlinks.json mal configurati, mancanti o
temporaneamente non disponibili. Problemi di rete durante la finestra critica in cui il browser
recupera questi file causeranno errori. Un punto cieco comune: se la tua homepage è inattiva
per manutenzione, anche i file well-known sono offline, interrompendo le cerimonie passkey
tra tutti i relying party che ne dipendono.Cosa vedrai nella console del browser:
| Origine | Messaggio di errore |
|---|---|
| Chrome, Edge | SecurityError: WebAuthn is not supported on sites with TLS certificate errors. |
| Qualsiasi browser | SecurityError: The relying party ID is not a registrable domain suffix of, nor equal to the current origin's effective domain. |
| Chrome (iframe) | SecurityError: The 'publickey-credentials-create' feature is not enabled in this document. |
In produzione, il SecurityError è raro: quasi sempre vengono rilevati durante i test
di integrazione. Quando compaiono, l'errore del certificato TLS è il sopravvissuto più comune.
Il ciclo di debug più veloce è:
publickey-credentials-create / publickey-credentials-get):
MDN Permissions-PolicyUna volta gestito SecurityError, il prossimo bucket da prendere sul serio è il set di errori
che spesso indicano bug di implementazione: InvalidStateError, ConstraintError e
DataError.

Cheatsheet Passkeys. Guide pratiche, pattern di distribuzione e KPI per programmi passkey.
Questi errori dovrebbero essere rari in un'implementazione passkey matura. Quando compaiono, in genere indicano che la generazione delle opzioni è errata per un segmento o che il flusso è nello stato sbagliato.
Cosa vedrai nella console del browser:
| Origine | Messaggio di errore |
|---|---|
| Safari, WebKit | InvalidStateError: The user attempted to register an authenticator that contains one of the credentials already registered with the relying party. |
| Chrome, Edge | InvalidStateError: At least one credential matches an entry of the excludeCredentials list in the platform attached authenticator. |
| Chrome, Edge | InvalidStateError: A request is already pending. |
| Firefox | InvalidStateError: An attempt was made to use an object that is not, or is no longer, usable |
Significati tipici:
Gestione pratica:
excludeCredentials elenchi tutti gli ID delle credenziali esistenti per l'utente, così
l'autenticatore può rilevare i duplicatiInvalidStateError è
previsto e dovrebbe essere ignorato silenziosamente: significa che esiste già una passkey nel
provider. Lo stesso vale per NotAllowedError e AbortError durante il
conditional create (vedi
conditional create on Chrome)Significato tipico: l'autenticatore non può soddisfare i vincoli richiesti.
Cause scatenanti comuni:
authenticatorAttachment o
resident key troppo severiuserVerification in segmenti in cui non sono disponibiliCorrezione: allenta i vincoli (dove accettabile) o fornisci un percorso alternativo. Per il blocco schermo mancante, considera di rilevare questa condizione e di guidare gli utenti piuttosto che fallire in silenzio (Android).
Significato tipico: gli input sono malformati o incoerenti.
Cause scatenanti comuni:
Correzione: convalida e normalizza gli input al confine in cui generi le opzioni WebAuthn. In
pratica, DataError è di fatto assente nei sistemi di produzione maturi: se la generazione delle
tue opzioni è testata, non la vedrai nelle dashboard.
Se questi errori sono sotto controllo, la domanda successiva riguarda la copertura: gli utenti falliscono perché l'ambiente non può eseguire WebAuthn nel modo in cui ti aspetti?
NotSupportedError è un segnale di copertura, non un segnale di affidabilità. Di solito significa che un
segmento non può eseguire ciò che hai richiesto (sistema operativo/browser troppo vecchio, capacità mancante, funzionalità non
abilitata).
Cosa vedrai nella console del browser:
| Origine | Messaggio di errore |
|---|---|
| Chrome, Edge | NotSupportedError: The user agent does not support public key credentials. |
| Firefox | NotSupportedError: Resident credentials or empty 'allowCredentials' lists are not supported. |
| Chrome, Edge, Firefox | TypeError: PublicKeyCredential.parseCreationOptionsFromJSON is not a function |
| Chrome, Edge, Firefox | TypeError: PublicKeyCredential.parseRequestOptionsFromJSON is not a function |
| Chrome, Edge, Firefox | TypeError: credential.toJSON is not a function |
| Safari | TypeError: Can only call PublicKeyCredential.toJSON on instances of PublicKeyCredential |
Le prime due sono vere e proprie NotSupportedError DOMException. Le voci TypeError sono
tecnicamente un tipo di eccezione diverso ma rappresentano la stessa classe di problemi: il
browser o l'ambiente non supporta ciò che hai richiesto. La famiglia TypeError legata alla
serializzazione JSON è molto più comune nella pratica rispetto all'eccezione
NotSupportedError vera e propria (vedi sotto).
Le cause comuni includono:
La famiglia della serializzazione JSON è la più grande fonte di fallimenti della classe NotSupportedError
in produzione. Tecnicamente, questi emergono come TypeError (metodo mancante), non
come DOMException, ma è qui che li incontrerai. Due cause alla radice distinte:
navigator.credentials ma non PublicKeyCredential.parseCreationOptionsFromJSON /
parseRequestOptionsFromJSON. Ciò rappresenta circa il 90% di questa famiglia di errori,
concentrata nelle versioni meno recenti di Safari e Chrome. Se la tua libreria client dipende da
questi metodi senza un fallback, ciò produce un volume di errori significativo..toJSON(). Le estensioni come
Bitwarden,
LastPass o
1Password possono intercettare la
cerimonia e restituire un oggetto che sembra una credenziale ma non è un'istanza
PublicKeyCredential reale. Chiamare .toJSON() su di esso genera un'eccezione, restituisce
undefined o l'oggetto è completamente null. Questo rappresenta circa il 10% della famiglia, ma
è particolarmente confuso da eseguire il debug perché i messaggi di errore differiscono in base al browser (Safari:
"Can only call on instances of PublicKeyCredential"; Firefox: "does not implement
interface PublicKeyCredential").La gestione dovrebbe essere diretta e veloce:
Se la copertura sembra a posto, ma i fallimenti si verificano ancora in segmenti specifici, potresti avere a
che fare con problemi a livello di piattaforma visualizzati come UnknownError.
UnknownError è un errore generico per i guasti dell'autenticatore/del sistema operativo che non si mappano in modo
pulito nelle altre categorie. È spesso temporaneo, ma può anche verificarsi con dei picchi dopo gli aggiornamenti del sistema operativo.
Cosa vedrai nella console del browser:
| Origine | Messaggio di errore |
|---|---|
| Chrome (Android) | UnknownError: An unknown error occurred while talking to the credential manager. |
| Qualsiasi browser | UnknownError: The operation failed for an unknown transient reason. |
| Qualsiasi browser | UnknownError: Either the device has received unexpected request data, or the device has been reconfigured since the request was made. |
| Qualsiasi browser | UnknownError: Something went wrong. |
| Chrome (LastPass) | TypeError: Cannot use 'in' operator to search for 'type' in null |
| Safari (LastPass) | TypeError: null is not an Object. (evaluating 'key in input') |
| Chrome (Bitwarden) | FallbackRequested |
Gestione pratica:
Una fonte di nicchia di errori che non si adatta bene a nessuna categoria DOMException:
estensioni del browser del gestore di password (come
Bitwarden,
LastPass,
1Password e altri) possono intercettare
le chiamate all'API WebAuthn e restituire risposte non standard. Sebbene di volume ridotto rispetto
agli annullamenti degli utenti, vale la pena monitorarli perché influenzano sistematicamente segmenti di
utenti specifici e i sintomi sono confusi: metodi mancanti sull'oggetto credenziale
restituito, tipi di errore imprevisti o risposte malformate che non corrispondono a nessun errore WebAuthn
documentato. Questi emergono spesso come UnknownError o come eccezioni non classificate. Se
vedi picchi di errori concentrati in browser specifici senza alcuna spiegazione a livello di sistema operativo, controlla
se è coinvolta un'estensione per la gestione delle credenziali.
Finora abbiamo coperto i nomi degli errori dei browser web. Ma se rilasci anche app native, il panorama degli errori è diverso e, per certi versi, nettamente migliore.
Tutto quanto sopra riguarda i browser web. Le app native - iOS con il framework ASAuthorization, Android con Credential Manager - condividono le stesse categorie fondamentali di errori ma differiscono in modo importante:
"Nessuna credenziale" è un segnale distinto. Sul web, i browser raggruppano "nessuna credenziale
disponibile" e "utente annullato" nello stesso NotAllowedError per motivi di privacy. Sulle versioni native,
utilizzare preferImmediatelyAvailableCredentials su iOS (ASAuthorizationController) o
setPreferImmediatelyAvailableCredentials(true) su
Android (GetCredentialRequest) indica al sistema operativo
di presentare solo le credenziali già presenti sul dispositivo e di fallire immediatamente se non ne esistono.
Ciò fornisce un segnale pulito di "nessuna credenziale" che il web non può fornire.
Lo stato del provider di credenziali è visibile. Sulle piattaforme native, in alcune condizioni, puoi
sapere quando nessun provider di credenziali (Google Password Manager,
iCloud Keychain,
1Password, ecc.) è installato,
configurato o impostato come predefinito e reagire a ciò. Sul web, queste
informazioni sono nascoste dietro messaggi NotAllowedError opachi.
I messaggi di errore sono più specifici. Poiché l'utente ha installato l'app - e di conseguenza ha stabilito un rapporto di fiducia con il relying party - il sistema operativo fornisce dettagli diagnostici maggiori. Le considerazioni sulla privacy che costringono i browser web a essere vaghi non si applicano allo stesso modo quando l'app è già sul dispositivo. iOS restituisce messaggi localizzati nella lingua del dispositivo dell'utente. Android restituisce tipi di errore strutturati con catene di cause. Questo rende più semplice il debugging ma significa che la gestione degli errori deve tenere conto della localizzazione e dei formati di errore specifici della piattaforma.
iOS espone gli errori delle passkey tramite il framework ASAuthorization. Tutti gli errori arrivano nel
callback del delegato authorizationController(controller:didCompleteWithError:) come
oggetti NSError.
Classifica per dominio + codice, non per stringa di messaggio. Il dominio di errore primario è
com.apple.AuthenticationServices.AuthorizationError
(ASAuthorizationError.errorDomain). Esegui il cast dell'errore con let nsError = error as NSError
e confrontalo su .domain e .code. Non effettuare mai il match su .localizedDescription in produzione -
I messaggi Apple sono localizzati in più di 30 lingue e possono cambiare a seconda delle versioni del sistema operativo. Le
stringhe di messaggio elencate di seguito sono utili per riconoscere gli errori nei log, ma non sono
criteri di classificazione.
Codici ASAuthorizationError pubblici:
| Codice | Nome | Da | Cosa significa |
|---|---|---|---|
| 1000 | Unknown | iOS 13 | Non dovrebbe apparire in produzione. Catch-all generico. |
| 1001 | Canceled | iOS 13 | L'utente ha chiuso il foglio delle passkey. L'errore più comune in assoluto - l'equivalente di NotAllowedError. Segnale pulito con userInfo vuoto e nessun errore di fondo. |
| 1002 | InvalidResponse | iOS 13 | Corruzione a livello di framework. Raro in pratica. |
| 1003 | NotHandled | iOS 13 | Nessun provider ha gestito la richiesta. Controlla gli entitlement e la configurazione del provider di credenziali. |
| 1004 | Failed | iOS 13 | Fallimento generico. Il localizedDescription contiene il motivo reale (ad es. "Application with identifier X is not associated with domain Y"). userInfo può contenere una stringa FailureReason, ma NSUnderlyingErrorKey non è sempre popolato: i guasti di associazione al dominio restituiscono nil per l'errore di fondo. |
| 1005 | NotInteractive | iOS 15 | Nessuna credenziale disponibile quando si utilizza preferImmediatelyAvailableCredentials. Questo è il segnale "not found" pulito - l'equivalente iOS di "nessuna passkey esiste su questo dispositivo". Non è stata mostrata alcuna interfaccia utente. |
| 1006 | MatchedExcludedCredential | iOS 18 | Esiste già una passkey per questo RP su questo dispositivo. Segnale pulito per il rilevamento di duplicati - userInfo vuoto, nessun NSUnderlyingErrorKey. La classificazione funziona senza il matching delle stringhe. |
| 1007 | CredentialImport | iOS 18.2 | Importazione credenziali non riuscita. |
| 1008 | CredentialExport | iOS 18.2 | Esportazione credenziali non riuscita. |
| 1009 | PreferSignInWithApple | iOS 26 | L'utente preferisce Accedi con Apple alla passkey. Nuovo in iOS 26. |
| 1010 | DeviceNotConfiguredForPasskeyCreation | iOS 26 | Il dispositivo è privo di passcode o configurazione di iCloud Keychain. Bug noto del simulatore iOS 26: restituisce 1010 anche quando la configurazione è corretta (non si riproduce sui dispositivi fisici). |
La distinzione più importante per la produzione: da iOS 18, le credenziali duplicate
restituiscono il proprio codice di errore 1006 (MatchedExcludedCredential). Su
iOS 17 e versioni precedenti, le credenziali duplicate erano nascoste
all'interno del codice 1004 (Failed). Su
iOS 18+, la distinzione è strutturale
(codice di errore diverso), non testuale.
Errori di runtime comuni (riferimento a livello di log):
Questi messaggi compaiono in localizedDescription o in userInfo per specifici scenari
di errore. Utilizzali per le ricerche nei log e il debugging, non per la classificazione a livello di codice.
| Messaggio (impostazioni locali inglese) | Codice di base | Note |
|---|---|---|
Application with identifier <TeamID.BundleID> is not associated with domain X | 1004 (Failed) | L'entitlement Associated Domains dell'app non corrisponde al relying party. Correggi il file apple-app-site-association sul tuo server. |
Couldn't communicate with a helper application. | 1004 (Failed) | L'estensione del provider di credenziali non ha risposto. Temporaneo: è opportuno riprovare. |
Request already in progress for specified application identifier. | 1004 (Failed) | Una richiesta ASAuthorization duplicata è stata avviata mentre ne era in sospeso un'altra. Race condition nell'app. |
Stolen Device Protection is enabled and biometry is required. | 1004 (Failed) | iOS 17+ Stolen Device Protection blocca l'autenticazione biometrica in luoghi non familiari. Non risolvibile dagli sviluppatori, ma vale la pena informare l'utente. |
(AuthenticationServicesCore.ASCABLEClient.ClientError error 2.) | Dominio separato | L'handshake Bluetooth dell'autenticazione cross-device (hybrid/CABLE) è fallito. |
(AuthenticationServicesCore.ASCABLEClient.ClientError error 3.) | Dominio separato | La connessione Bluetooth dell'autenticazione cross-device è fallita. |
Messaggi localizzati "nessuna credenziale" (codice 1005):
Quando preferImmediatelyAvailableCredentials è impostato e non esiste alcuna passkey, iOS restituisce
il codice 1005 (NotInteractive) con un messaggio localizzato nella lingua del dispositivo
dell'utente. Ciò è esclusivo delle app native: i browser web non espongono mai questo segnale. Il messaggio inizia sempre
con The operation couldn't be completed. seguito dal testo localizzato:
| Lingua | Messaggio |
|---|---|
| Cinese (Semplificato) | 没有可用于登录的凭证。 |
| Vietnamita | Không có sẵn thông tin để đăng nhập. |
| Arabo | لا تتوفر بيانات اعتماد لتسجيل الدخول. |
| Spagnolo | No hay ninguna credencial disponible para iniciar sesión. |
| Cinese (Tradizionale) | 沒有可用於登入的憑證。 |
| Coreano | 로그인을 위한 자격 증명이 없습니다. |
| Francese (Canada) | Aucun identifiant disponible pour la connexion. |
| Portoghese (Brasile) | Nenhuma credencial disponível para login. |
| Francese (Francia) | Aucune information d'identification n'est disponible pour procéder à la connexion. |
| Tailandese | ไม่มีข้อมูลประจำตัวสำหรับเข้าสู่ระบบ |
| Italiano | Non ci sono credenziali disponibili per l'accesso. |
| Olandese | Geen inloggegevens beschikbaar. |
| Giapponese | ログイン用の資格情報がありません。 |
| Turco | Oturum açmak için kullanılabilecek kimlik bilgisi yok. |
I dispositivi in lingua inglese in genere risolvono l'errore "nessuna credenziale" a livello di API prima che il framework ASAuthorization restituisca un errore localizzato, motivo per cui non appare alcuna variante inglese qui sopra. A livello di codice, fai sempre affidamento sul codice 1005 anziché analizzare queste stringhe.
Android mostra gli errori delle passkey tramite l'API Credential Manager
(androidx.credentials). I messaggi di errore includono un messaggio principale e spesso un cause
con ulteriori dettagli. Rispetto a iOS, Android fornisce tipi di errore più strutturati e
cause più esplicite per i problemi di configurazione.
Annullamento dell'utente e rilevamento delle credenziali:
| Errore | Note |
|---|---|
User cancelled the operation | L'utente ha chiuso il prompt passkey. L'equivalente di NotAllowedError. Nota: il Credential Manager restituisce anche User canceled the request (ortografia USA) da un percorso di codice diverso - entrambi sono identici. |
Excluded credential matches existing credential | Esiste già una passkey per questo ID credenziale. L'equivalente di InvalidStateError. A differenza di iOS, il messaggio è distinto dall'annullamento dell'utente. |
No create options available. | Nessun provider di credenziali idoneo può gestire la richiesta di creazione. In genere significa che i Google Play Services sono obsoleti o che nessun provider di credenziali supporta la creazione di passkey. |
Errori di configurazione e sicurezza:
| Errore | Note |
|---|---|
Passkeys not supported for this app | I Digital Asset Links (assetlinks.json) mancano o non contengono l'impronta digitale del certificato di firma dell'app. L'equivalente di SecurityError. |
Https failed: respCode=301, url=https://<domain>/.well-known/assetlinks.json | Il file assetlinks.json restituisce un reindirizzamento invece di un HTTP 200. Android richiede il file all'URL esatto senza reindirizzamenti. |
The incoming request cannot be validated | Il Credential Manager non può verificare la richiesta tramite Digital Asset Links. |
RP ID cannot be validated. | Il relying party ID nelle opzioni WebAuthn non corrisponde a assetlinks.json. |
Screen lock is missing. | Nessun PIN, sequenza o dato biometrico configurato sul dispositivo. Le passkey richiedono la verifica dell'utente. L'equivalente di ConstraintError. |
Cannot find an eligible account. | Nessun account Google sul dispositivo è idoneo per la creazione della passkey (raro, in genere configurazioni aziendali personalizzate). |
Errori della piattaforma e dell'autenticatore:
| Errore | Note |
|---|---|
Unsuccessful result from folsom activity. | Fallimento interno ai Google Play Services. "Folsom" è un componente GMS per le operazioni passkey. Temporaneo: è opportuno riprovare. |
Can't find the proper key to decrypt the private key from WebauthnCredentialSpecifics. | Esiste una passkey sincronizzata ma il dispositivo non può decrittografare la sua chiave privata. Lo stato di sincronizzazione del Google Password Manager è incoerente: la credenziale è stata sincronizzata da un altro dispositivo ma la chiave di decrittografia non è disponibile. Non risolvibile dagli sviluppatori. |
Operation was interrupted (cause: The UI was interrupted - please try again.) | L'interfaccia utente del Credential Manager è stata interrotta da un'altra attività (chiamata in arrivo, rotazione dello schermo, app in background). L'equivalente di AbortError. |
Unknown credential error | Un errore catch-all generico quando non si applica alcun tipo di errore specifico. Solitamente transitorio. |
timeout (cause: Canceled) | L'operazione del Credential Manager è andata in timeout prima che l'utente completasse la verifica biometrica. |
Il diagramma seguente mostra come tutti i livelli descritti in precedenza (infrastruttura, ambiente, tipo di operazione, classificazione e rilevamento) si connettono da un'estremità all'altra. È il modello mentale da tenere a mente quando si progetta il tracciamento degli errori.
L'intuizione chiave: un error.name non elaborato ha senso solo quando sai quale livello dell'
ambiente lo ha prodotto, quale operazione era in esecuzione e se l'errore era previsto o
imprevisto. Le sezioni sottostanti descrivono cosa registrare e come agire di conseguenza.
La maggior parte della classificazione degli errori in questo articolo può essere eseguita solo con i segnali lato client. Un SDK di osservabilità solo frontend acquisisce abbastanza contesto per classificare la stragrande maggioranza degli errori WebAuthn. Questo è anche il modo in cui è architettato l'SDK di osservabilità di Corbado: il livello lato client gestisce l'attribuzione degli errori, le tempistiche, il contesto dell'operazione e il rilevamento della piattaforma. La registrazione lato server aggiunge un secondo livello per i guasti che solo il backend può vedere.
Il requisito chiave: ogni tentativo deve essere rintracciabile da un capo all'altro. Un id di correlazione condiviso
(ad esempio auth_flow_id) collega il contesto lato client con l'esito della verifica del server.
| Segnale | Perché è importante |
|---|---|
error.name + motivo normalizzato | Errore raw del browser + la tua classificazione |
| Tipo di operazione | Conditional UI, login modale, creazione manuale, conditional create, auto-append. CDA (Cross-Device Auth) è una complessità a sé stante. |
| Contesto ambientale completo | OS + versione, browser + versione, marca/modello hardware, impostazioni dell'autenticatore (es. GPM abilitato?) |
| Contesto dell'autenticatore/del manager | Rotture delle estensioni e del provider |
| Tempo trascorso prima dell'errore | Rifiuto immediato (<1s) vs annullamento dell'utente (1-15s) vs timeout (30s+) |
| Stato della rete/connettività | Gli errori di rete spesso si manifestano come errori client. Tieni traccia se l'utente era offline e metti in coda i log da inviare al ripristino. |
| Se è apparsa la UI QR/ibrida | Fallimento locale vs cross-device |
Id di correlazione (auth_flow_id) | Collega con i log del server |
I fallimenti della verifica lato server si verificano dopo che il browser ha restituito una credenziale e
una challenge firmata. Questi dovrebbero essere errori strutturati con codici espliciti, e non mescolati nello
stesso bucket dei nomi delle DOMException lato client.
| Segnale | Perché è importante |
|---|---|
| Mancata corrispondenza / challenge scaduta | Problemi di tempistiche della sessione o di replay |
| Origine / mancata corrispondenza dell'RP ID | Bug di configurazione multi-dominio |
| Firma non valida / credenziale non trovata | Credenziale eliminata o corrotta. Caso comune: accesso con Conditional UI con una passkey che l'utente ha già eliminato lato server. Usa la Signal API per mantenere sincronizzati gli elenchi di credenziali client e server. |
| Mancata corrispondenza dell'handle utente | Problemi di mappatura dell'account |
Id di correlazione (auth_flow_id) | Collega con il contesto lato client |
Se desideri un modello a imbuto completo (drop-off in base allo step e conversione tra gli step), vedi l' analisi della telemetria delle passkey.
Iscriviti al nostro Substack sulle passkey per le ultime novità.
Con questi dati in atto, la conclusione diventa semplice: la maggior parte degli "errori" si trasforma in correzioni della UX, correzioni della copertura o correzioni di configurazione. Ma costruire e mantenere questa classificazione da soli è un notevole lavoro continuo.
La checklist di logging mostrata sopra acquisisce segnali raw. Nella produzione su larga scala,
error.name da solo non è sufficiente. Costruire questa classificazione da solo è un lavoro notevole e
continuo: i messaggi di errore cambiano a ogni release di browser e sistema operativo,
i fornitori di password manager distribuiscono aggiornamenti che alterano
il comportamento delle cerimonie e nuove firme di errori appaiono con il lancio di ogni funzionalità.
error.name da solo non è sufficiente#Lo stesso NotAllowedError può significare sei cose diverse a seconda di tre dimensioni
che i browser non separano per te:
| Dimensione | Cosa ti danno i browser | Cosa ti serve effettivamente | Esempio |
|---|---|---|---|
| Contesto dell'operazione | NotAllowedError | È stato un conditional UI, login modale, creazione manuale, conditional create o auto-append? | Android restituisce lo stesso "unknown error" per un login annullato (previsto) e una creazione fallita (imprevisto) |
| Tempistiche | Nessun dato sulla durata | Rifiuto immediato (<1s) vs annullamento utente (1-15s) vs timeout (30s+) | 200ms = rifiuto ambiente; 5s = l'utente ha visto la finestra e ha annullato; 35s = timeout |
| Piattaforma + auth | error.name generico | OS, browser, versione, gestore credenziali per ogni errore | "l'utente ha chiuso la finestra" su Chrome e "autofill non disponibile" su Safari emergono entrambi come NotAllowedError |
Questo è il problema che l'SDK di osservabilità di Corbado è concepito per risolvere. È una leggera integrazione frontend che si sovrappone alla tua implementazione passkey esistente, funziona con qualsiasi server WebAuthn e qualsiasi IDP e classifica automaticamente ogni errore WebAuthn lungo tutte e tre le dimensioni:
| Capacità | Cosa fa |
|---|---|
| Attribuzione degli errori | Acquisisce sistema operativo, versione OS, browser, versione browser e autenticatore a ogni tentativo di cerimonia |
| Modalità operativa | Collega ogni errore all'operazione specifica (conditional UI, login modale, creazione manuale, conditional create, auto-append) in modo che lo stesso NotAllowedError si risolva in cause radice differenti |
| Tempistiche dall'inizio dell'azione | Registra la durata dall'avvio della cerimonia per distinguere i rifiuti immediati, gli annullamenti degli utenti e i timeout senza dover indovinare |
| Classificazione intelligente | Mappa il contesto completo dell'errore (non solo il nome), normalizzando tra diversi Ambienti (OS, hardware, impostazioni). Dà priorità a gruppi di errore distinti come CDA vs Locale e distingue gli errori Previsti (Annullamento Utente) da quelli Imprevisti (Guasto Sistema). |
| Frammentazione dei gestori di pwd | Rileva quando le estensioni di gestione credenziali (Bitwarden, 1Password, LastPass) intercettano le cerimonie e restituiscono risposte non standard, separando i guasti causati dall'estensione da quelli della piattaforma |
Questo è il livello Observe: visibilità su ciò che sta accadendo, senza cambiare la tua implementazione.
La console di gestione di Corbado supporta due percorsi di indagine:
Top-down (dalla dashboard alla causa radice):
Bottom-up (dai modelli di errore all'impatto):
Entrambi i percorsi convergono: il top-down ti dice che qualcosa non va, il bottom-up ti dice perché. L' AI Analytics Assistant connette i due consentendoti di porre domande in linguaggio naturale sia sui dati degli errori che sulle metriche di adozione.
I team che desiderano agire su questi segnali possono passare ad Adopt, che aggiunge la passkey intelligence per limitare automaticamente le cerimonie, ottimizzare i prompt di registrazione e ripristinare gli stati interrotti delle passkey. Per ambienti regolamentati o implementazioni su larga scala, Enterprise aggiunge l' hosting single-tenant, l'integrazione SIEM e la configurazione conforme alla PSD2.
Ottieni un whitepaper gratuito sulle passkey per aziende.
I nomi degli errori WebAuthn non sono un verdetto. Sono dei suggerimenti e diventano utilizzabili solo quando li colleghi al tipo di operazione, alle tempistiche e al contesto della piattaforma.
NotAllowedError), ciclo di vita dell'app/concorrenza (AbortError), contesto/configurazione di sicurezza (SecurityError), o bug di opzioni/stato (InvalidStateError, ConstraintError, DataError). La stragrande maggioranza del volume è formata da NotAllowedError, e la maggior parte di questi è un comportamento previsto (l'utente ha chiuso il prompt).NotAllowedError? Usa le tempistiche (rifiuto immediato vs annullamento utente vs timeout), un indicatore QR/ibrido (mancata corrispondenza della disponibilità), il contesto di attivazione dell'utente (soprattutto su iOS/Safari) e il tipo di operazione (conditional UI vs login modale vs creazione passkey vs conditional create). Non trattare tutti i NotAllowedError come un'unica modalità di fallimento.error.name durante un
login con conditional UI è un segnale completamente diverso rispetto a
durante un conditional create o una creazione manuale di passkey (l'utente ha ignorato la finestra).
La registrazione del tipo di operazione insieme all'errore è ciò che trasforma il generico NotAllowedError
in un bucket azionabile.error.name, il tipo di operazione,
il tempo trascorso prima dell'errore dall'inizio dell'operazione, il tipo di flusso, se è stata mostrata l'interfaccia utente QR/ibrida,
il sistema operativo/browser/dispositivo (comprese le versioni), un id di correlazione (auth_flow_id) e i rifiuti di verifica del server
come codici espliciti.Due regole pratiche che si applicano a tutti i tipi di errore: non mostrare mai agli utenti gli errori raw del browser (fornisci sempre un chiaro percorso di fallback) e separa i tentativi locali da quelli QR/ibridi tra più dispositivi, perché falliscono per motivi diversi e necessitano di correzioni diverse. Su larga scala, mantenere la classificazione degli errori attraverso browser, versioni del sistema operativo e gestori di credenziali è un lavoro continuo. Valuta l'utilizzo di un SDK di osservabilità con una libreria di pattern gestita anziché costruire tutto da zero.
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 →
Sul web, i browser raggruppano entrambi i casi in NotAllowedError per motivi di privacy, quindi
non puoi distinguerli direttamente. Usa le tempistiche come proxy: un errore sotto a 1 secondo in genere
significa un rifiuto da parte dell'ambiente o l'assenza di capacità, mentre un lasso di tempo di 1-15 secondi suggerisce che l'utente ha
visto e chiuso la finestra di dialogo. Sulle app native per iOS e Android, l'impostazione di
preferImmediatelyAvailableCredentials prima della richiesta fornisce un segnale pulito di "nessuna credenziale" (codice iOS 1005, Android GetCredentialRequest) prima ancora che venga mostrata un'interfaccia utente.
Nelle implementazioni ottimizzate di passkey su larga scala, oltre il 95% degli errori WebAuthn registrati
sono annullamenti previsti dall'utente, non guasti di sistema. Il tracciamento dei conteggi raw di error.name senza
separare "l'utente ha chiuso il prompt" dai guasti veri e propri gonfia le metriche degli errori e nasconde
delle reali regressioni tra i volumi dei NotAllowedError. Dividi i tuoi conteggi in base al tipo di
operazione e tratta i bucket di annullamenti utente separatamente da errori inattesi come
SecurityError, ConstraintError e DataError.
Il codice iOS 1005 (NotInteractive) significa che nessuna passkey era disponibile sul dispositivo quando
preferImmediatelyAvailableCredentials è stato impostato su ASAuthorizationController e non è stata
mostrata alcuna UI all'utente. Questo è il segnale pulito "nessuna passkey esiste su questo dispositivo" che
i browser web non possono fornire a causa dei vincoli di privacy. Classifica sempre sul
codice numerico, non su localizedDescription, perché i messaggi Apple sono localizzati in più di 30
lingue e possono cambiare tra le varie versioni del sistema operativo.
Durante il conditional create, NotAllowedError, AbortError e InvalidStateError sono tutti
risultati previsti e dovrebbero essere ignorati silenziosamente anziché fatti emergere come errori.
NotAllowedError indica che l'autofill non è disponibile o che la pagina ha perso il focus, mentre
InvalidStateError significa che una passkey esiste già nel provider. Prima di tentare la
chiamata, usa getClientCapabilities() per verificare il supporto al conditionalCreate e controlla lo stato
di visibilità del documento per evitare di gonfiare i tuoi conteggi di errore.
Acquisisci il tipo di operazione (conditional UI, login modale, creazione manuale, conditional create o auto-append), il tempo trascorso prima dell'errore, la versione del sistema operativo, la versione del browser, il modello
hardware, se è apparso l'elemento QR/ibrido nell'interfaccia e un ID di correlazione da collegare ai log del lato server. I fallimenti
nella verifica del server come la challenge errata, la firma non valida e la credenziale non trovata
dovrebbero essere registrati come codici espliciti strutturati, non raggruppati nello stesso bucket
insieme ai nomi DOMException del lato client. Questi segnali, sommati fra loro, consentono la classificazione della stragrande
maggioranza degli errori in bucket azionabili, senza dover tirare a indovinare.
Scopri come Corbado si integra con la tua distribuzione di passkey e con lo stack di autenticazione esistente.
Esplora la Console
Articoli correlati
Indice