Trang này được dịch tự động. Đọc phiên bản gốc bằng tiếng Anh tại đây.
Trong môi trường production, các lỗi WebAuthn thường gây nhầm lẫn vì các trình duyệt hiển thị một tập hợp nhỏ các tên DOMException (như NotAllowedError) có thể đại diện cho nhiều nguyên nhân cơ bản. Hơn thế nữa, phần lớn các "lỗi" - thường trên 95% trong các đợt triển khai quy mô lớn được tối ưu hóa - thực chất là hành vi dự kiến (người dùng đã hủy lời nhắc passkey của hệ điều hành).
Thử nghiệm các luồng passkey trong Passkeys Debugger.
Quan trọng: Vì lý do bảo mật quyền riêng tư, các trình duyệt không phân biệt việc người dùng chủ động hủy hay không có passkey nào tồn tại. Tuy nhiên, trong một số tình huống và với đủ ngữ cảnh, cả trên web và nền tảng native, một số trường hợp này có thể được phân biệt bằng cách sử dụng các tín hiệu như thời gian.
Nếu bạn muốn có các định nghĩa chuẩn xác cho những tên này, hãy bắt đầu với MDN DOMException. Để biết các điều kiện cụ thể của WebAuthn dẫn đến những ngoại lệ này (và những gì trình duyệt bắt buộc phải thực thi), hãy xem Thông số kỹ thuật Web Authentication của W3C.
Nếu bạn coi mọi lỗi là "bug", bạn sẽ thực hiện sai những việc sau:
NotAllowedErrorTrong bài viết này, chúng tôi trả lời:
NotAllowedError thành các nhóm có thể xử lý (hủy bỏ, quá thời gian, tình trạng sẵn có)?Bài viết gần đây
⚙️
Tài liệu Cheat Sheet về Passkey cho Lập trình viên
👤
Cách Xóa Passkey trên Apple, Windows và Android
📖
Giải thích Kỹ thuật về WebAuthn Conditional UI (Tự động điền Passkey)
📖
Hướng dẫn toàn diện về lỗi WebAuthn trong môi trường Production (2026)
📖
Passkey trên Brave Browser (2026): Điều gì hoạt động và điều gì bị lỗi
NotAllowedError là tín hiệu bề mặt, không phải nguyên nhân cốt lõi. Nó có thể có nghĩa là hủy bỏ, quá thời gian, "không có thông tin xác thực cục bộ" hoặc thiếu sự kích hoạt của người dùng tùy thuộc vào ngữ cảnh.NotAllowedError có ý nghĩa khác nhau trong quá trình đăng nhập conditional UI, đăng nhập modal, tạo passkey thủ công, conditional create và thao tác nối thêm được kích hoạt tự động.<1s), người dùng hủy (1-15s) và quá thời gian (30s+) là các danh mục hoàn toàn khác nhau.AbortError thường là sự cố vòng đời/đồng thời (điều hướng, render lại, nhiều yêu cầu đang xử lý).SecurityError gần như luôn là cấu hình/ngữ cảnh và hiếm gặp trong các đợt triển khai production hoàn thiện.error.name để bạn có thể phân loại các lỗi thành các nhóm mà bạn thực sự có thể sửa chữa.Nếu bạn chỉ cần một sơ đồ phân loại nhanh để gỡ rối quá trình sửa lỗi, hãy bắt đầu với bảng này. Nó tập trung vào những gì các nhóm thực sự thấy trong dashboard và các ticket hỗ trợ.
error.name | Ý nghĩa thường gặp trong production | Cần kiểm tra gì để xác nhận | Hành động đầu tiên (UX + kỹ thuật) |
|---|---|---|---|
NotAllowedError | Người dùng đã đóng bảng điều khiển, hết thời gian chờ hoặc không khớp tính khả dụng đều gộp chung vào một nhóm. Đây là nhóm lỗi lớn nhất. | thời gian đến khi lỗi, liệu mã QR/giao diện người dùng kết hợp có xuất hiện không, liệu nghi thức có bắt đầu từ một hành động của người dùng không | Coi như bình thường: khôi phục UI + hiển thị phương án dự phòng |
AbortError | Ứng dụng của bạn (hoặc trình duyệt) đã hủy bỏ nghi thức | điều hướng/hiển thị lại trong quá trình; các lệnh gọi WebAuthn đồng thời; AbortController.abort() | Bắt buộc có một yêu cầu đang xử lý; ngăn chặn thay đổi định tuyến; xử lý lỗi hủy như luồng điều khiển bình thường |
SecurityError | Ngữ cảnh/chính sách không được phép | chiến lược origin + RP ID; iframe/nhúng; HTTPS; tính năng policy | Khắc phục cấu hình RP ID/origin; xác nhận các chính sách nhúng; đảm bảo ngữ cảnh an toàn |
InvalidStateError | Trạng thái không khớp (thường là đăng ký trùng lặp) | đăng ký với đăng nhập; excludeCredentials; thông tin xác thực hiện tại trên trình xác thực | Coi như “đã đăng ký”; điều chỉnh đường dẫn UX; sửa lại phần tạo tùy chọn |
ConstraintError | Không thể đáp ứng các yêu cầu | authenticatorAttachment, userVerification, yêu cầu khóa thường trú | Nới lỏng ràng buộc hoặc cung cấp đường dẫn/phương án dự phòng thay thế. Ví dụ: Khóa màn hình bị thiếu trên Android |
DataError | Dữ liệu đầu vào bị sai lệch/không nhất quán | mã hóa base64url; định dạng id/challenge/user handle | Khắc phục việc mã hóa/sắp xếp chuỗi; thêm xác thực trong phần tạo tùy chọn |
NotSupportedError | Nền tảng/trình duyệt không hỗ trợ những gì bạn yêu cầu | Hệ điều hành/phiên bản trình duyệt; giả định phát hiện tính năng | Trở lại trạng thái mặc định ngay lập tức; ghi chú phân đoạn; tránh hiển thị CTA passkey cho các môi trường không được hỗ trợ |
UnknownError | Nền tảng/trình xác thực thất bại theo một cách chung chung | tăng đột biến sau khi cập nhật hệ điều hành; số hiệu bản dựng thiết bị; lỗi nhà cung cấp trình quản lý thông tin xác thực | Giao diện người dùng thân thiện với tính năng thử lại; ghi lại các số hiệu bản dựng; điều tra các mức tăng đột biến theo phân đoạn |
Một điều dễ bỏ sót: cùng một error.name có thể mang ý nghĩa rất khác nhau tùy thuộc vào loại hoạt động. Hãy luôn lưu ý ngữ cảnh hoạt động khi bạn đọc các phần bên dưới. Trong thực tế, các lỗi tạo passkey (đăng ký) thường nhiều hơn lỗi đăng nhập rất nhiều - bảng trên áp dụng cho cả hai, nhưng phần tạo mới là nơi tập trung khối lượng lớn.
Tiếp theo, chúng ta sẽ đi sâu hơn vào NotAllowedError vì đây là lỗi bạn sẽ thấy nhiều nhất và là lỗi mà các nhóm thường hiểu sai nhất.
NotAllowedError thường giống như "passkeys thất bại", nhưng nó thường là nền tảng đang báo cho bạn biết người dùng đã không hoàn thành UI của hệ điều hành. Chìa khóa ở đây là chia nó thành các nhóm mà bạn có thể xử lý.
Những gì bạn sẽ thấy trong bảng điều khiển trình duyệt:
| Nguồn | Thông báo lỗi |
|---|---|
| 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. |
Tất cả những lỗi này hiển thị dưới dạng error.name === "NotAllowedError". error.message khác nhau tùy theo công cụ trình duyệt và nguyên nhân cơ bản, nhưng kết quả đều giống nhau: nghi thức không hoàn tất.
Điều này áp dụng cho cả đăng nhập và tạo passkey. Trong quá trình đăng nhập (conditional UI, modal có hoặc không có allowList), NotAllowedError thường có nghĩa là người dùng đã không hoàn thành nghi thức. Trong quá trình tạo passkey, cùng một lỗi hiển thị vì nhiều lý do khác nhau: người dùng đã đóng hộp thoại tạo, conditional create không hoạt động, hoặc trang bị mất tiêu điểm trong quá trình thao tác nối thêm được kích hoạt tự động. Loại hoạt động thay đổi ý nghĩa của lỗi và những gì bạn nên làm với nó.
Thời gian thường là một tín hiệu bị đánh giá thấp. Một lỗi xảy ra dưới 1 giây sau khi nhấp chuột thường là từ chối ngay lập tức (môi trường không thể làm được, tài liệu không được chú ý, thiếu khả năng). Một lỗi xảy ra sau vài giây là do người dùng hủy bỏ (họ thấy hộp thoại và quyết định không tiếp tục). Một lỗi sau hơn 30 giây là đã quá thời gian. Trên các nền tảng native, thời gian đặc biệt quan trọng: thời gian khứ hồi của authenticator, lời nhắc sinh trắc học và quá trình chuyển giao ứng dụng quản lý mật khẩu đều có khoảng thời gian đặc trưng giúp bạn phân biệt "không hiệu quả" với "người dùng đã rời đi". Bạn vẫn không thể dễ dàng phân biệt được liệu một passkey có tồn tại hay không.
Bạn không cần một tín hiệu hoàn hảo. Bạn cần đủ ngữ cảnh để tránh việc đối xử với mọi lỗi NotAllowedError theo cùng một cách. iOS/Safari nhận được sự chú ý đặc biệt ở bên dưới vì nó có những hạn chế riêng (yêu cầu kích hoạt người dùng ở các phiên bản trước), nhưng về số lượng lỗi thô, các trình duyệt Windows và Chromium thường tạo ra nhiều lỗi NotAllowedError hơn bất kỳ nền tảng nào khác. Những tín hiệu này thường giúp bạn đi được 80% chặng đường:
| Tín hiệu | Ý nghĩa có thể | Làm gì tiếp theo |
|---|---|---|
Lỗi ngay lập tức (<1s) | Môi trường từ chối: không có khả năng, trang không được chú ý, bề mặt conditional create không có sẵn | Kiểm tra xem có hỗ trợ tính năng không; đảm bảo trang đang được chú ý; xác nhận hoạt động này được hỗ trợ trên nền tảng này |
| Hủy nhanh (1-3s) | Nhắc nhở bất ngờ / không có ngữ cảnh | Thay đổi thời gian nhắc nhở; thêm thời gian chờ sau khi hủy |
| Thời gian hủy của người dùng (3-15s) | Người dùng đã nhìn thấy hộp thoại và chọn không tiếp tục | UX dự kiến; khôi phục UI + hiển thị phương án dự phòng |
| Hết thời gian chờ (30s+) | Nghi thức đã quá thời gian mà không có thao tác từ người dùng | Nhóm lại là "không hoàn tất"; xem xét liệu lời nhắc nhở có được chú ý hay không |
| Giao diện mã QR/kết hợp xuất hiện trước khi bị lỗi | Không có thông tin xác thực cục bộ trên thiết bị này. Lưu ý: Việc phát hiện sớm các quyết định mã QR yêu cầu một lớp passkey intelligence có thể nhận diện liệu chứng nhận nào có thể sử dụng đang tồn tại trên thiết bị hiện tại không. | Tạo cổng các đề nghị mật mã khóa; hiển thị tùy chọn "Sử dụng điện thoại" rõ ràng; giảm mã QR bất ngờ |
| Tập trung trên iOS/Safari và bị kích hoạt mà không có click/chạm | Thiếu kích hoạt từ người dùng | Bắt đầu nghi thức từ một thao tác thực tế của người dùng |
| Trong quá trình conditional create hoặc tự động đính kèm | Tự động điền không có sẵn, thông tin đăng nhập đã tồn tại, hoặc trang không được chú ý. Các lỗi conditional create có thể xuất hiện đột ngột và với số lượng lớn khi tính năng được tung ra, biến nó thành một trong những nguồn lỗi lớn nhất chỉ trong một đêm. | Xem conditional create; kiểm tra trạng thái khả năng hiển thị của trang; sử dụng getClientCapabilities() để xác nhận sự hỗ trợ của conditionalCreate trước khi thử gọi |
Đây cũng là lý do tại sao NotAllowedError hiếm khi nên hiển thị cho người dùng. Nó không phải là thông báo mà người dùng có thể thực hiện.
Việc phân loại theo bối cảnh cũng là lúc tỷ lệ thành công bị chia cắt mạnh nhất. Phân tích tỷ lệ thành công của passkey đo lường tỷ lệ hoàn thành ở Q1 2026 đạt 55-95% cho các luồng xác định thiết bị chưa biết so với 95-99% đối với thiết bị đã biết trả về trên các triển khai B2C quy mô lớn.
Nhận dạng nền tảng web iOS trước tiên đạt 85-95% hoàn thành (CDA 0-5%), nền web Android ở 70-85% (CDA 5-10%) và nền web macOS ở 70-85% (CDA 10-15%), trong khi nền web Windows nằm ở mức 45-60% với %CDA ở 55-65% trên Windows 11 và 40-55% trên Windows 10. Đọc khối lượng NotAllowedError mà không chia thiết bị đã biết với chưa biết kết hợp hai cơ chế tỷ lệ thành công hoàn toàn khác nhau.
Một sắc thái quan trọng trong production: một số tác nhân người dùng có thể hiển thị hết thời gian dưới dạng TimeoutError, nhưng nhiều nhóm vẫn thấy tình trạng hết thời gian chờ được thu gọn thành NotAllowedError trong trang tổng quan. Dù bằng cách nào, hãy coi hết thời gian chờ là “nghi thức không hoàn thành” và phân nhóm sử dụng thời gian cùng ngữ cảnh.
Khi bảng điều khiển hệ điều hành bị tắt hoặc hết thời gian chờ, UI của bạn phải ngay lập tức được khôi phục lại và phản ứng mượt mà. Một số quy tắc thực tế:
Ngoài những điều cơ bản:
Nếu tỷ lệ “lượt hủy” thực sự cao, bước tiếp theo là khắc phục nguyên nhân gốc rễ đằng sau: thời gian xuất hiện của lời nhắc, những bất ngờ từ mã QR và mức độ sẵn có thấp.
NotAllowedError#Hãy bắt đầu với những thay đổi có thể nhanh chóng cải thiện các số liệu:
NotAllowedError của bạn. Hãy bắt đầu với isUVPAA() như rào cản cơ bản nhất, sau đó sử dụng getClientCapabilities() cho những yêu cầu kiểm tra kỹ càng hơn (conditional create, conditional get, vận chuyển lai, trình xác thực nền tảng). Lưu ý rằng các API phát hiện có thể bị gián đoạn cùng với những lần cập nhật hệ điều hành: iOS 26.2 phát hành với một lỗi trên WebKit trong đó isUVPAA() trả về giá trị false đối với tất cả những trình duyệt có nền tảng WKWebView mặc dù passkey hoạt động hoàn toàn bình thường, dẫn tới đột biến đột ngột ở lỗi NotAllowedError đối với 10-25% số lượng người dùng iOS.Tên lỗi là một mục tiêu luôn di chuyển. Đã có những đề xuất đang được thực hiện để thêm nhiều các lỗi chi tiết hơn liên quan đến WebAuthn (ví dụ, để chia ra “không có thông tin xác nhận” với “người dùng đã hủy”). Tính đến tháng 2 năm 2026, điều này vẫn chưa được áp dụng vào bất kỳ trình duyệt nào, nên tốt nhất là xây dựng hệ thống các nhóm lý do để phân loại nguyên nhân cho riêng mình dựa trên ngữ cảnh và thời gian. Nếu bạn muốn theo dõi hoạt động này, xin hãy xem WebAuthn issue #2062 và bảng giải thích "Mã Lỗi Mới".
Những lỗi khác sẽ xuất hiện ít thường xuyên hơn nhưng vẫn đáng để tìm hiểu khi chúng xuất hiện.
Lỗi AbortError ít khi xuất hiện với số lượng nhiều nếu so với lỗi NotAllowedError, nhưng khi nó xảy ra, lỗi này thường là chẩn đoán mức cao: nghĩa là nghi thức không hoàn thiện bởi vì ứng dụng của bạn không cho yêu cầu được duyệt - điều hướng xảy ra, trạng thái thay đổi hoặc một yêu cầu thứ hai đã được khởi động.
Bạn sẽ gặp những lỗi nào trên giao diện trình duyệt:
| Nguồn | Thông báo lỗi |
|---|---|
| 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. |
Những nguyên nhân thường gặp trong môi trường production bao gồm:
AbortController.abort() trong lúc chờ thử lại hoặc lúc chờ dọn dẹp hệ thốngĐể giải quyết, hãy tập trung vào việc tạo cho những nghi thức một “khu vực kiểm soát”:
Nếu bạn bắt gặp lỗi AbortError xuất hiện đặc ở những bề mặt được đính kèm hoặc trong những ứng dụng hỗ trợ nhiều tên miền, phần tiếp theo bạn nên kiểm tra chính là SecurityError.
SecurityError là cách trình duyệt thông báo rằng: "bối cảnh này không được phép làm những gì bạn vừa bảo." Về thực tế thì hầu hết tất cả lỗi đều nằm trên cấu hình chứ không phải trên thao tác của người dùng. Trong các đợt phát hành ở production, SecurityError là rất hiếm bởi vì những lỗi trên thường được tìm thấy khi kiểm tra tích hợp. Khi nó hiện lên trên giao diện hoạt động thì có nghĩa là một domain mới, bối cảnh đính kèm hay một nơi điều hướng vừa mới được thêm vào mà thiếu đi các cấu hình WebAuthn hỗ trợ.
Những nguyên do thông dụng bao gồm:
.well-known/webauthn hay .well-known/assetlinks.json bị cấu hình sai, bị mất hoặc tạm thời không thể sử dụng. Những lỗi trên hệ thống mạng trong quá trình cần thiết nhất khi mà trình duyệt thu thập thông tin từ những tập tin này sẽ gây ra thất bại. Một góc khuất mà rất nhiều người dùng không để ý: nếu web chính của bạn phải bảo trì, thì những file public này cũng sẽ offline, làm gián đoạn mọi nghi thức liên quan tới WebAuthn của bạn đối với tất cả những bên lệ thuộc vào nó.Bạn sẽ gặp những lỗi nào trên giao diện trình duyệt:
| Nguồn | Thông báo lỗi |
|---|---|
| Chrome, Edge | SecurityError: WebAuthn is not supported on sites with TLS certificate errors. |
| Any 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. |
Trong môi trường production, SecurityError là rất hiếm - hầu hết chúng thường được tìm thấy và loại bỏ trong thời gian kiểm tra. Nếu chúng vẫn xuất hiện, thì lỗi trên chứng chỉ TLS là những lý do duy nhất có khả năng xảy ra nhất.
Vòng lập debug nhanh nhất là:
publickey-credentials-create / publickey-credentials-get): MDN Permissions-PolicyMột khi lỗi SecurityError được giải quyết, những loại lỗi tiếp theo mà bạn cần phải giải quyết kỹ lưỡng là những lỗi thường thể hiện rõ về bug đã được cài đặt: InvalidStateError, ConstraintError và DataError.

Cheatsheet Passkeys. Hướng dẫn thực tế, mẫu triển khai và KPI cho chương trình passkeys.
Các lỗi này hiếm khi xảy ra trong một hệ thống passkey hoàn thiện. Khi chúng xuất hiện, chúng thường chỉ ra rằng phần tạo tùy chọn (option generation) bị sai cho một nhóm nhất định hoặc quy trình đang ở sai trạng thái.
Những gì bạn sẽ thấy trong bảng điều khiển trình duyệt:
| Nguồn | Thông báo lỗi |
|---|---|
| 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 |
Ý nghĩa thông thường:
Xử lý thực tế:
excludeCredentials liệt kê tất cả credential ID hiện có của người dùng để authenticator có thể phát hiện lỗi trùng lặpInvalidStateError là điều được dự kiến và nên được bỏ qua một cách lặng lẽ: điều đó có nghĩa là passkey đã tồn tại trong nhà cung cấp. Điều tương tự áp dụng cho NotAllowedError và AbortError trong quá trình conditional create.Ý nghĩa thông thường: authenticator không thể đáp ứng các ràng buộc mà bạn yêu cầu.
Nguyên nhân phổ biến:
authenticatorAttachment hoặc khóa thường trúuserVerification trong các nhóm mà chúng không có sẵnCách khắc phục: nới lỏng các ràng buộc (khi có thể chấp nhận) hoặc cung cấp một hướng đi thay thế. Đối với thiết bị thiếu khóa màn hình, hãy xem xét phát hiện tình trạng này và hướng dẫn người dùng thay vì thất bại lặng lẽ (Android).
Ý nghĩa thông thường: đầu vào bị biến dạng hoặc không nhất quán.
Nguyên nhân phổ biến:
Cách khắc phục: xác minh và chuẩn hóa các đầu vào ở ranh giới nơi bạn tạo WebAuthn options. Trong thực tế, DataError gần như vắng bóng trong các hệ thống production trưởng thành - nếu option generation của bạn đã được thử nghiệm, bạn sẽ không thấy điều này trong dashboard.
Nếu các lỗi này đang được kiểm soát, câu hỏi tiếp theo là phạm vi hỗ trợ: người dùng có thất bại vì môi trường không thể thực hiện WebAuthn theo cách bạn mong đợi?
NotSupportedError là một tín hiệu về độ bao phủ, không phải tín hiệu về độ tin cậy. Nó thường có nghĩa là một phân khúc không thể làm những gì bạn yêu cầu (HĐH/trình duyệt quá cũ, thiếu khả năng, tính năng không được kích hoạt).
Những gì bạn sẽ thấy trong bảng điều khiển trình duyệt:
| Nguồn | Thông báo lỗi |
|---|---|
| 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 |
Hai dòng đầu tiên là các DOMException thực sự cho NotSupportedError. Các mục TypeError về mặt kỹ thuật là một loại ngoại lệ khác nhưng đại diện cho cùng một lớp vấn đề: trình duyệt hoặc môi trường không hỗ trợ những gì bạn đã yêu cầu. Lớp chuỗi hóa JSON TypeError phổ biến hơn nhiều trong thực tế so với bản thân DOMException NotSupportedError.
Nguyên nhân phổ biến bao gồm:
Lớp chuỗi hóa JSON là nguồn lớn nhất gây ra lỗi thuộc lớp NotSupportedError trong môi trường production. Về kỹ thuật, chúng hiển thị là TypeError (thiếu phương thức) chứ không phải là DOMException, nhưng đây là nơi bạn sẽ gặp chúng. Hai nguyên nhân gốc rễ khác biệt:
navigator.credentials nhưng không có PublicKeyCredential.parseCreationOptionsFromJSON / parseRequestOptionsFromJSON. Điều này chiếm khoảng 90% gia đình lỗi này, tập trung ở các phiên bản Safari và Chrome cũ hơn. Nếu thư viện client của bạn phụ thuộc vào các phương thức này mà không có dự phòng, thì điều này sẽ tạo ra lượng lỗi đáng kể..toJSON(). Các tiện ích mở rộng như Bitwarden, LastPass, hoặc 1Password có thể chặn buổi lễ và trả về một đối tượng trông giống như thông tin xác thực nhưng không phải là phiên bản thực sự của PublicKeyCredential. Việc gọi .toJSON() trên đó có thể ném ra lỗi, trả về undefined, hoặc đối tượng hoàn toàn là null. Điều này chiếm khoảng 10% nhưng đặc biệt gây bối rối để gỡ lỗi vì các thông báo lỗi khác nhau tùy theo trình duyệt.Xử lý nên dứt khoát và nhanh chóng:
Nếu phạm vi hỗ trợ có vẻ ổn định nhưng vẫn gặp lỗi ở các nhóm thiết bị cụ thể, bạn có thể đang xử lý các sự cố ở tầng nền tảng được hiển thị thông qua UnknownError.
UnknownError là một khái niệm tổng hợp để chỉ các lỗi về trình xác thực/hệ điều hành không phù hợp để xếp vào các loại lỗi khác. Thường đây chỉ là vấn đề tạm thời nhưng nó cũng có thể tăng vọt sau khi cập nhật hệ điều hành.
Những lỗi bạn sẽ thấy trên bảng điều khiển trình duyệt:
| Nguồn | Thông báo lỗi |
|---|---|
| Chrome (Android) | UnknownError: An unknown error occurred while talking to the credential manager. |
| Mọi trình duyệt | UnknownError: The operation failed for an unknown transient reason. |
| Mọi trình duyệt | UnknownError: Either the device has received unexpected request data, or the device has been reconfigured since the request was made. |
| Mọi trình duyệt | 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 |
Cách xử lý trong thực tế:
Một nguồn lỗi nhỏ không phù hợp với loại DOMException: các tiện ích mở rộng về trình quản lý mật khẩu của trình duyệt (như Bitwarden, LastPass, 1Password, và những ứng dụng khác) có thể chặn cuộc gọi API WebAuthn và đưa ra các phản hồi phi tiêu chuẩn. Dù không nhiều nhưng đây là những lỗi cần theo dõi vì chúng ảnh hưởng nhất quán đến các phân khúc người dùng cụ thể và những triệu chứng đi kèm thì rất khó hiểu: phương pháp không có trong đối tượng xác thực được trả về, loại lỗi bất ngờ, hoặc các phản hồi bất thường không phù hợp với thông tin lỗi WebAuthn đã cung cấp. Chúng thường sẽ hiển thị dưới dạng UnknownError hoặc dạng ngoại lệ chưa phân loại. Nếu bạn thấy tỉ lệ gặp lỗi tăng cao ở các trình duyệt cụ thể mà không có lý giải cho cấp độ hệ điều hành, hãy kiểm tra xem có sự can thiệp của tiện ích mở rộng nào không.
Từ nãy đến giờ chúng ta đã nhắc qua tất cả các tên lỗi trên trình duyệt web. Nhưng nếu bạn sử dụng các ứng dụng native thì bức tranh tổng thể về lỗi sẽ khác biệt - và có phần tốt hơn nhiều.
Tất cả những thông tin bên trên là dành cho các trình duyệt web. Ứng dụng native - iOS với khung cấu trúc ASAuthorization, Android với Credential Manager - đều chia sẻ các nhóm lỗi cơ bản chung nhưng khác biệt ở các điểm quan trọng sau:
"Không có credentials" là một tín hiệu khác biệt. Trên web, các trình duyệt sẽ gộp hai trường hợp "không có credential khả dụng" và "người dùng hủy" vào chung một loại lỗi NotAllowedError vì các lý do liên quan đến bảo mật quyền riêng tư. Trên nền tảng native, việc dùng lệnh preferImmediatelyAvailableCredentials trên iOS (ASAuthorizationController) hoặc setPreferImmediatelyAvailableCredentials(true) trên Android (GetCredentialRequest) sẽ báo cho hệ điều hành chỉ hiện các loại credential đã có sẵn trong thiết bị và báo lỗi ngay nếu không tìm thấy. Từ đó ta sẽ thu được một lệnh "không có credentials" rõ ràng mà trên nền tảng web không thể làm được.
Trạng thái về nhà cung cấp credential được hiển thị. Nền tảng native trong một số điều kiện có thể thông báo cho bạn khi không có nhà cung cấp credential nào (Google Password Manager, iCloud Keychain, 1Password, v.v.) được cài đặt, được định cấu hình, hoặc được cài mặc định và phản hồi lại. Trên web, loại thông tin này bị ẩn sau các thông báo lỗi NotAllowedError khó hiểu.
Thông báo lỗi mang tính chi tiết hơn. Khi người dùng đã tải app về, hệ điều hành sẽ hiển thị chi tiết các lỗi chẩn đoán sâu hơn. Các lý do liên quan đến bảo mật quyền riêng tư làm cho trình duyệt web mù mờ sẽ không áp dụng ở đây khi mà ứng dụng đã được tải về. iOS sẽ hiển thị thông báo với ngôn ngữ được thiết bị sử dụng. Android hiển thị các loại lỗi có cấu trúc cùng với chuỗi phân tích. Từ đó giúp cho việc sửa lỗi dễ hơn nhưng đồng nghĩa với việc bạn phải biết nguyên do xảy ra lỗi với dạng lỗi của hệ điều hành hiện tại.
iOS xuất lỗi passkey bằng khung cấu trúc ASAuthorization. Tất cả lỗi sẽ chuyển về authorizationController(controller:didCompleteWithError:) dưới dạng đối tượng NSError.
Phân nhóm dựa vào domain và code, không phải vào tin nhắn. Main error domain là com.apple.AuthenticationServices.AuthorizationError (ASAuthorizationError.errorDomain). Cast lỗi với let nsError = error as NSError và gán với .domain và .code. Đừng bao giờ chọn .localizedDescription trong lúc đang phát hành bản production - tin nhắn của Apple được dịch qua hơn 30 ngôn ngữ và có thể thay đổi trên các phiên bản hệ điều hành. Các dòng tin nhắn phía dưới rất hữu dụng trong việc nhận biết các lỗi trong bản báo cáo nhưng lại không phải là tiêu chí để ta phân loại lỗi.
Mã lỗi Public ASAuthorizationError:
| Code | Tên | Since | Ý nghĩa |
|---|---|---|---|
| 1000 | Unknown | iOS 13 | Lỗi không xuất hiện trong bản product. |
| 1001 | Canceled | iOS 13 | Lỗi tương đương NotAllowedError. Người dùng tắt danh sách passkey. Đây là lỗi phổ biến nhất - loại tín hiệu sạch (clean signal) có chỉ số rỗng trên userInfo và không ẩn chứa các lỗi tiềm tàng. |
| 1002 | InvalidResponse | iOS 13 | Hỏng hóc liên quan đến cấp độ khung cấu trúc. Hiếm gặp trong lúc thực hành. |
| 1003 | NotHandled | iOS 13 | Request không được provider nào giải quyết. Kiểm tra lại thông tin về provider và quyền lợi (entitlements). |
| 1004 | Failed | iOS 13 | Thất bại chung chung. localizedDescription mang lý do chính xác (ví dụ "Application with identifier X is not associated with domain Y"). userInfo có thể có chuỗi FailureReason, nhưng NSUnderlyingErrorKey không phải lúc nào cũng được sử dụng - lỗi domain sẽ trả lại chỉ số bằng 0 (nil) cho phần lỗi tiềm tàng (underlying error). |
| 1005 | NotInteractive | iOS 15 | Không có credentials khả dụng khi đang dùng preferImmediatelyAvailableCredentials. Đây là báo hiệu cho biết passkey không tồn tại. Tương tự như iOS, không có tín hiệu UI hiện lên. |
| 1006 | MatchedExcludedCredential | iOS 18 | RP này đã có một loại passkey riêng trên thiết bị. Clean signal dùng để dò xem có passkey nào bị lập lại không - làm trống userInfo, không có NSUnderlyingErrorKey. Có thể thực hiện phân nhóm lỗi mà không cần gắn với string. |
| 1007 | CredentialImport | iOS 18.2 | Quá trình nạp credential thất bại. |
| 1008 | CredentialExport | iOS 18.2 | Quá trình xuất credential thất bại. |
| 1009 | PreferSignInWithApple | iOS 26 | Người dùng chuộng sử dụng Sign in with Apple hơn dùng passkey. Xuất hiện lần đầu trong iOS 26. |
| 1010 | DeviceNotConfiguredForPasskeyCreation | iOS 26 | Thiết bị không có mật khẩu hoặc cấu hình iCloud Keychain. Lỗi được biết đến trong bộ mô phỏng trên iOS 26: hệ thống xuất 1010 mặc dù cấu hình vẫn đúng (không xuất hiện trên các thiết bị vật lý). |
Sự khác biệt quan trọng nhất cho môi trường production: từ iOS 18, credential trùng lặp sẽ trả lại mã code riêng 1006 (MatchedExcludedCredential). Ở iOS 17 trở xuống, credential trùng lặp được giấu trong dòng code 1004 (Failed). Ở iOS 18+, sự khác biệt nằm ở cấu trúc (mã code khác nhau), chứ không phải là ở văn bản.
Các lỗi runtime phổ biến (tham khảo cấp độ nhật ký):
Những tin nhắn này xuất hiện trong phần localizedDescription hoặc trong userInfo cho từng trường hợp lỗi cụ thể. Hãy dùng chúng để tìm kiếm nhật ký và sửa lỗi, đừng dùng chúng để phân loại theo lập trình.
| Message (English locale) | Underlying code | Ghi chú |
|---|---|---|
Application with identifier <TeamID.BundleID> is not associated with domain X | 1004 (Failed) | Phần phân quyền Các tên miền liên quan (Associated Domains) của app không hợp với bên cung cấp thứ 3. Khắc phục tệp apple-app-site-association trên máy chủ của bạn. |
Couldn't communicate with a helper application. | 1004 (Failed) | Hệ thống không phản hồi lại ứng dụng cung cấp loại chứng chỉ mở rộng. Chỉ là lỗi tạm thời - xin thử lại lần nữa. |
Request already in progress for specified application identifier. | 1004 (Failed) | Một bản sao của yêu cầu ASAuthorization đã được phát trong khi một cái khác vẫn đang chờ xử lý. Tình trạng chạy đua trong app (Race condition in the app). |
Stolen Device Protection is enabled and biometry is required. | 1004 (Failed) | Phần Mất Thiết bị An toàn (Stolen Device Protection) trên iOS 17 trở lên chặn xác minh sinh trắc học đối với những vị trí lạ. Developer không thể làm gì nhưng hãy báo cho người dùng. |
(AuthenticationServicesCore.ASCABLEClient.ClientError error 2.) | Phân miền riêng biệt | Xác thực giữa nhiều thiết bị với nhau (dạng lai/CABLE) qua quá trình thiết lập Bluetooth thất bại. |
(AuthenticationServicesCore.ASCABLEClient.ClientError error 3.) | Phân miền riêng biệt | Kết nối Bluetooth ở hai thiết bị khi xác thực thất bại. |
Thông điệp nội địa hóa "không có thông tin xác thực" (code 1005):
Khi sử dụng preferImmediatelyAvailableCredentials và không có passkey nào, iOS sẽ trả về mã lỗi 1005 (NotInteractive) đi kèm với ngôn ngữ địa phương mà thiết bị sử dụng. Điều này là đặc quyền ở các ứng dụng native - các web browser không có loại tín hiệu này. Loại thông báo này luôn bắt đầu với phần The operation couldn't be completed. theo sau đó là thứ ngôn ngữ được thiết bị sử dụng:
| Ngôn ngữ | Tin nhắn |
|---|---|
| Chinese (Simplified) | 没有可用于登录的凭证。 |
| Vietnamese | Không có sẵn thông tin để đăng nhập. |
| Arabic | لا تتوفر بيانات اعتماد لتسجيل الدخول. |
| Spanish | No hay ninguna credencial disponible para iniciar sesión. |
| Chinese (Traditional) | 沒有可用於登入的憑證。 |
| Korean | 로그인을 위한 자격 증명이 없습니다. |
| French (Canada) | Aucun identifiant disponible pour la connexion. |
| Portuguese (Brazil) | Nenhuma credencial disponível para login. |
| French (France) | Aucune information d'identification n'est disponible pour procéder à la connexion. |
| Thai | ไม่มีข้อมูลประจำตัวสำหรับเข้าสู่ระบบ |
| Italian | Non ci sono credenziali disponibili per l'accesso. |
| Dutch | Geen inloggegevens beschikbaar. |
| Japanese | ログイン用の資格情報がありません。 |
| Turkish | Oturum açmak için kullanılabilecek kimlik bilgisi yok. |
Các thiết bị ở chế độ ngôn ngữ tiếng Anh thường sẽ giải quyết lệnh "không có thông tin xác nhận" này tại cấp độ API trước khi cấu trúc ASAuthorization gửi lại một mã lỗi dạng địa phương hóa, đó là lý do mà không có phiên bản nào của tiếng Anh xuất hiện ở phần trên. Về mặc lập trình, mã lỗi code 1005 thay vì phân tích các đoạn chữ đó.
Android hiển thị các lỗi liên quan đến passkey qua ứng dụng lập trình giao diện Credential Manager (androidx.credentials). Thông báo của nó bao gồm một thông báo chính cùng với nguyên do được giải thích vô cùng tỉ mỉ. Nếu so với iOS, Android lại cung cấp nhiều loại lỗi với cấu trúc hoàn chỉnh hơn và lý do cũng vô cùng dễ hiểu so với phần lý do của ứng dụng kia.
Người dùng từ chối thao tác & phân loại chứng chỉ:
| Lỗi | Lưu ý |
|---|---|
User cancelled the operation | Người dùng tắt prompt về passkey. Nó có dạng giống với lỗi NotAllowedError. Chú ý: Ứng dụng quản lý xác minh trả về User canceled the request (phiên bản đánh vần bằng tiếng anh Mỹ) từ một đường đi dữ liệu khác. |
Excluded credential matches existing credential | Có một loại chứng chỉ hiện đang tồn tại (tương tự như InvalidStateError). Loại thông báo này hoàn toàn khác biệt so với lời từ chối của người dùng. |
No create options available. | Không có nhà cung cấp xác nhận đạt tiêu chuẩn nào xử lý phần tạo yêu cầu này. Thường có nghĩa là do dịch vụ từ cửa hàng ứng dụng đã lỗi thời hoặc ứng dụng không hỗ trợ. |
Lỗi về cấu hình và bảo mật:
| Lỗi | Lưu ý |
|---|---|
Passkeys not supported for this app | Đường dẫn kĩ thuật số (assetlinks.json) đã bị mất hoặc không thể dò ra được dấu vân tay của ứng dụng này (tương tự như lỗi SecurityError). |
Https failed: respCode=301, url=https://<domain>/.well-known/assetlinks.json | Hệ thống báo lỗi cho tệp tin assetlinks.json vì nó trả lại dạng URL chuyển hướng thay vì URL HTTP 200. Android đòi hỏi yêu cầu file phải hoàn hảo. |
The incoming request cannot be validated | Ứng dụng Credential Manager không thể kiểm chứng tính chính xác của các đường link đã cung cấp. |
RP ID cannot be validated. | Phụ thuộc trên các thông tin ID đã cung cấp trong các ứng dụng WebAuthn nhưng nó lại không hợp với assetlinks.json. |
Screen lock is missing. | Máy không được thiết lập mã pin, kiểu màn hình khóa hay một chế độ đăng nhập bảo mật nào khác. Tính năng passkey đòi hỏi tính bảo mật cá nhân (Tương tự ConstraintError). |
Cannot find an eligible account. | Không có một tài khoản google khả dụng nào cho ứng dụng này (hiếm gặp, thường là đối với các loại tài khoản doanh nghiệp đã qua điều chỉnh từ người dùng). |
Nền tảng hệ điều hành và lỗi của ứng dụng bên xác thực:
| Lỗi | Ghi chú |
|---|---|
Unsuccessful result from folsom activity. | Sự cố lỗi nội bộ trong Google Play. Dịch vụ "Folsom" là hệ thống thông số kỹ thuật (GMS) cho công đoạn cấp quyền đăng nhập (tạm thời - vui lòng thử lại). |
Can't find the proper key to decrypt the private key from WebauthnCredentialSpecifics. | Tính năng đồng bộ passkey đã được mở nhưng không được giải mã bởi máy chủ do ứng dụng quản lý mật khẩu Google không thể đồng bộ hóa khóa đồng bộ hóa giữa nhiều loại máy chủ khác nhau do không giải được chuỗi mật mã gốc (từ ứng dụng bên thứ 3) từ đó dẫn tới lỗi không mong muốn. |
Operation was interrupted (cause: The UI was interrupted - please try again.) | Giao diện của công cụ quản lý xác minh bị thao túng bởi một hoạt động (cuộc gọi đến, thay đổi màn hình khóa, ứng dụng trên máy) từ ứng dụng khác (tương đương với AbortError). |
Unknown credential error | Một loại lỗi chung (chỉ xảy ra khi chưa thể phân loại hệ thống thông báo được). Thường thì sẽ là dạng lỗi tạm thời. |
timeout (cause: Canceled) | Quá trình quản lý chứng chỉ bị quá thời gian trước khi người dùng kịp hoàn thành phần bảo mật sinh trắc học. |
Biểu đồ sau đây sẽ cho thấy cách tất cả các tầng được thảo luận ở trên - Hạ tầng (Infrastructure), Môi trường (Environment), Loại hoạt động (Operation type), Phân loại (Classification) và Phát hiện (Detection) - kết nối từ đầu đến cuối như thế nào. Đây là mô hình tinh thần bạn nên ghi nhớ khi thiết kế hệ thống theo dõi lỗi của mình.
Hiểu biết quan trọng nhất là: một tham số dạng error.name thô chỉ có thể hiểu được khi bạn xác định tầng lớp nào trong Environment tạo ra lỗi, Operation (Loại hoạt động) nào đang diễn ra và liệu lỗi là do được dự kiến hay không. Dưới đây là những cách để có thể lưu trữ lịch sử báo cáo lỗi.
Phần lớn các phân loại lỗi trong bài viết này có thể được thực hiện chỉ với tín hiệu ở phía máy khách. Một SDK quan sát front-end sẽ thu thập đủ bối cảnh cần thiết cho việc phân nhóm hầu hết các loại lỗi về chứng chỉ WebAuthn. Đây cũng là cách SDK quan sát của Corbado được thiết kế: tầng phía máy khách xử lý việc quy chụp lỗi, thời gian, ngữ cảnh hoạt động và phát hiện nền tảng. Nhật ký phía máy chủ bổ sung thêm lớp thứ hai cho các lỗi mà chỉ backend mới có thể thấy.
Yêu cầu chính: mỗi lần thử cần được kết nối từ đầu đến cuối một cách trơn tru. Một ID tương quan dùng chung (ví dụ: auth_flow_id) sẽ kết nối thông tin phía khách hàng cùng với kết quả kiểm tra phía server.
| Tín hiệu | Lý do quan trọng |
|---|---|
error.name + nhóm lý do chuẩn hóa | Lỗi trình duyệt thô + phân loại của bạn |
| Loại hoạt động | Conditional UI, đăng nhập modal, tạo thủ công, conditional create, nối thêm tự động. CDA (Xác thực đa thiết bị) là một nhóm riêng phức tạp. |
| Ngữ cảnh Môi trường đầy đủ | HĐH + Phiên bản, Trình duyệt + Phiên bản, Thương hiệu/Mẫu Phần cứng, Cài đặt Authenticator (ví dụ: GPM đã kích hoạt?) |
| Ngữ cảnh Authenticator / trình quản lý | Extension và nhà cung cấp bị gián đoạn |
| Thời gian từ khi bắt đầu | Bị từ chối ngay lập tức (<1s) so với người dùng hủy (1-15s) so với quá thời gian (30s+) |
| Trạng thái Mạng / Kết nối | Lỗi mạng thường hiển thị thành lỗi phía máy khách. Theo dõi xem người dùng có bị offline và hàng đợi log để gửi ngay khi kết nối lại bình thường hay không. |
| Mã QR/hybrid UI có hiển thị không | Lỗi thiết bị so với lỗi xuyên nền tảng thiết bị |
Correlation id (auth_flow_id) | Để ghép với các log ở phía bên server |
Sự cố kiểm tra server là một phần sau khi trình duyệt trả lại kết quả chứng chỉ và challenge đã được đăng kí. Đây nên là loại mã lỗi định dạng chi tiết cấu trúc thay vì lưu tại cùng một nơi với các loại tên ngoại lệ DOMException. Đọc phần: WebAuthn Server Implementation.
| Tín hiệu | Lý do quan trọng |
|---|---|
| Sự bất đồng / lỗi quá hạn challenge | Thời gian cho một session hoặc sự lặp lại phiên có vấn đề |
| Lỗi Origin / RP ID mismatch | Thiết lập cấu hình hệ thống bao gồm nhiều tên miền bị sai |
| Cấu trúc / ID credential sai lệch | Bị gỡ khỏi hệ thống hay file bị lỗi. Một trường hợp điển hình nhất: thao tác truy cập sử dụng Conditional UI nhưng người dùng lại gỡ trên phía server. Hãy sử dụng Signal API để giữ mọi thông tin credential không bị sai. |
| Không đúng quy định về định dạng tên | Việc phân loại, quy trình gán thông tin account có vấn đề |
Dấu vết tương quan chung (auth_flow_id) | Liên kết với thiết bị cá nhân để dò thêm phần gốc (context) |
Nếu bạn cần tham khảo cho phễu thông tin (rút gọn hoặc loại bỏ các nhóm khách/đối tượng đã truy cập phễu thông qua các thao tác ở từng bước nhỏ): hãy vào trang passkey telemetry to understand drop-offs.
Đăng ký Passkeys Substack để nhận tin mới nhất.
Với dữ liệu này, kết luận trở nên đơn giản: hầu hết các "lỗi" đều có thể được xử lý bằng các bản sửa lỗi UX, bản sửa lỗi phạm vi hỗ trợ hoặc bản sửa lỗi cấu hình. Tuy nhiên, việc xây dựng và duy trì sự phân loại này cho riêng bạn đòi hỏi nhiều công sức liên tục.
Danh sách cần ghi log ở trên ghi lại các tín hiệu thô. Trong môi trường production ở quy mô lớn, chỉ riêng error.name là không đủ. Việc tự xây dựng hệ thống phân loại này đòi hỏi nỗ lực liên tục: các thông báo lỗi thay đổi theo từng bản phát hành trình duyệt và HĐH, các nhà cung cấp ứng dụng quản lý mật khẩu đưa ra các bản cập nhật làm thay đổi hành vi của buổi lễ và các dấu hiệu lỗi mới xuất hiện với mỗi đợt ra mắt tính năng.
error.name là không đủ#Cùng một NotAllowedError có thể mang 6 ý nghĩa khác nhau dựa trên ba tiêu chí mà trình duyệt không tách biệt cho bạn:
| Tiêu chí | Những gì trình duyệt cung cấp | Những gì bạn thực sự cần | Ví dụ |
|---|---|---|---|
| Ngữ cảnh hoạt động | NotAllowedError | Là conditional UI, đăng nhập modal, tạo thủ công, conditional create, hay nối thêm tự động? | Android trả về cùng một "unknown error" cho cả lượt đóng đăng nhập (dự kiến) và lỗi khi tạo (không dự kiến) |
| Thời gian | Không có dữ liệu độ dài | Ngay lập tức (<1s) so với người dùng hủy (1-15s) so với quá thời gian (30s+) | 200ms = môi trường từ chối; 5s = người dùng thấy hộp thoại và hủy; 35s = quá thời gian |
| Nền tảng + authenticator | Lỗi error.name chung chung | HĐH, trình duyệt, phiên bản, trình quản lý thông tin xác thực cho mỗi lỗi | "người dùng đã đóng hộp thoại" trên Chrome và "autofill không khả dụng" trên Safari đều xuất hiện dưới dạng NotAllowedError |
Đây là vấn đề mà SDK observability của Corbado được xây dựng để giải quyết. Nó là một tích hợp frontend gọn nhẹ, nằm trên hệ thống triển khai passkey hiện có của bạn, hoạt động với bất kỳ máy chủ WebAuthn nào và bất kỳ IDP nào, và tự động phân loại từng lỗi WebAuthn dựa trên cả ba tiêu chí:
| Khả năng | Chức năng thực hiện |
|---|---|
| Quy chụp lỗi | Nắm bắt HĐH, phiên bản HĐH, trình duyệt, phiên bản trình duyệt và trình xác thực sau mỗi lần thử |
| Chế độ hoạt động | Kết nối từng lỗi với hoạt động cụ thể (conditional UI, đăng nhập modal, tạo thủ công, conditional create, nối thêm tự động) để cùng một NotAllowedError được quy về những nguyên nhân gốc rễ khác nhau |
| Đo thời gian từ lúc bắt đầu | Ghi nhận khoảng thời gian từ lúc khởi chạy để phân biệt giữa tình trạng từ chối ngay lập tức, người dùng hủy và quá thời gian mà không cần phỏng đoán |
| Phân loại lỗi thông minh | So khớp trên ngữ cảnh lỗi đầy đủ (không chỉ cái tên), chuẩn hóa xuyên suốt những Môi trường khác nhau (HĐH, Phần cứng, Cài đặt). Ưu tiên các nhóm lỗi phân biệt như CDA so với Local, và phân biệt lỗi Dự kiến (Người dùng hủy) so với lỗi Không dự kiến (Lỗi Hệ thống). |
| Sự phân mảnh ứng dụng mật khẩu | Phát hiện khi các extension trình quản lý mật khẩu (Bitwarden, 1Password, LastPass) chặn ngang và trả về phản hồi phi tiêu chuẩn, phân biệt lỗi do extension so với lỗi nền tảng |
Đây là tầng Quan sát (Observe): khả năng hiển thị chi tiết về những gì đang xảy ra mà không cần thay đổi quá trình triển khai của bạn.
Bảng điều khiển quản lý của Corbado hỗ trợ hai đường hướng điều tra:
Top-down (Từ dashboard đến nguyên nhân gốc rễ):
Bottom-up (Từ các loại lỗi đến hậu quả):
Tất cả các con đường đều dẫn tới: "top-down" báo cho bạn một thông tin xấu, trong khi "bottom-up" sẽ cho bạn biết về lý do đó. Hệ thống Phân tích Báo cáo từ AI hỗ trợ liên kết hai chiều với việc trả lời những câu hỏi từ các văn bản tự nhiên qua dữ liệu liên quan đến lỗi và việc cải thiện các số liệu đo lường.
Các nhóm muốn khắc phục hoặc tận dụng lại các thông tin này có thể thông qua Adopt - phần mềm cung cấp những chứng chỉ tình báo (passkey intelligence) giúp khởi tạo giao diện điều hướng tự động trên web, tối ưu hóa quá trình đăng ký chứng chỉ và sửa chữa thông tin lỗi trên passkey. Đối với những môi trường được quy định nghiêm ngặt hay có thông tin dữ liệu cực lớn, bản Enterprise có thể cấp quyền single-tenant hosting, cùng với SIEM integration và hệ thống tương thích cho PSD2.
Nhận whitepaper passkey miễn phí cho doanh nghiệp.
Các loại lỗi WebAuthn không phải là định kiến cuối cùng. Chúng chỉ là các gợi ý - và chúng sẽ chỉ trở nên quan trọng khi bạn có khả năng kết nối và tìm ra các loại dữ liệu hoạt động đang có trên trình duyệt, thời gian và quá trình xử lý của nền tảng mà bạn dùng.
NotAllowedError), dữ liệu ứng dụng (AbortError), ngữ cảnh/cấu hình bảo mật (SecurityError), hay trạng thái phân quyền (InvalidStateError, ConstraintError, DataError). Phần lớn quy mô trong môi trường sẽ nằm ở NotAllowedError, phần nhiều cũng chính là loại thông tin dễ dự kiến nhất (người dùng từ chối thao tác).NotAllowedError? Dùng thời gian (bị từ chối ngay lập tức so với người dùng hủy bỏ và hết thời gian chờ), bộ quy chuẩn QR/công cụ hybrid (thông tin không khớp/khả dụng), dữ liệu thông tin về phân quyền kích hoạt (đặc biệt là iOS/Safari) và cách chúng vận hành (thông qua Conditional UI với hình thức modal log trên passkey hay là từ Conditional create). Đừng coi tất cả NotAllowedError là một loại lỗi hoạt động chung biệt.error.name nhưng khi ở trình thông báo của conditional UI lại là các mã code hoàn toàn khác biệt so với khi ở trình điều hướng cho conditional create, hoặc là phần thiết lập passkey truyền thống. Xác minh một log thuộc về loại nào cùng chung với loại lỗi đó là chìa khóa duy nhất chuyển NotAllowedError thành một loại lỗi có thể quản lý được.error.name, loại hoạt động, thời lượng, loại hình đang sử dụng, và liệu có phải là hình thức ứng dụng/thiết lập lai nào đã được mở lên không, Hệ điều hành (hay trình duyệt, ứng dụng), cùng với thông tin kết nối (auth_flow_id) và các đoạn mã lỗi server rõ ràng.Hai nguyên tắc vàng được áp dụng trên tất cả mọi loại lỗi: đừng bao giờ để người dùng nhìn thấy các lỗi thô của trình duyệt - luôn tạo cho họ một cách để dự phòng một cách rõ ràng nhất - và nên chia các cách quản lý cục bộ của nội bộ riêng và không được dính líu gì với hệ thống ngoại bộ khi có vấn đề. Các thiết lập và những phương pháp trên đôi khi phải tùy chỉnh cho phù hợp dựa theo phần cứng để tránh phát sinh ra nhiều hơn vì chúng sẽ gây rối hoặc bị can thiệp bởi mã bảo vệ của máy/ứng dụng bảo vệ của bên thứ 3 nên không có công thức cho mọi trường hợp. Ở những hệ thống quy mô lớn, liên kết các loại máy, những bản cập nhật của từng loại sẽ giúp cho việc phát hiện ra lỗi trở nên thường xuyên hơn. Nếu có thể, hãy dùng observability SDK được kết hợp từ nhiều thông số khác nhau thay vì làm mới từ ban đầu.
Corbado là Authentication Intelligence Platform dành cho các đội CIAM vận hành xác thực consumer ở quy mô lớn. Chúng tôi giúp bạn nhìn thấy điều mà log IDP và các công cụ analytics thông thường không thấy: những thiết bị, phiên bản OS, trình duyệt và trình quản lý credential nào hỗ trợ passkey, tại sao quá trình đăng ký không chuyển thành đăng nhập, luồng WebAuthn fail ở đâu, và khi nào một bản cập nhật OS hay trình duyệt làm hỏng đăng nhập một cách âm thầm — tất cả mà không cần thay thế Okta, Auth0, Ping, Cognito hay IDP nội bộ của bạn. Hai sản phẩm: Corbado Observe bổ sung observability cho passkey và mọi phương thức đăng nhập khác. Corbado Connect mang đến managed passkey với analytics tích hợp (song hành cùng IDP của bạn). VicRoads vận hành passkey cho hơn 5M người dùng với Corbado (kích hoạt passkey +80%). Trao đổi với chuyên gia Passkey →
Trên web, các trình duyệt gộp cả hai trường hợp vào NotAllowedError vì lý do bảo mật quyền riêng tư, do đó bạn không thể phân biệt chúng trực tiếp. Hãy sử dụng thời gian làm yếu tố thay thế: lỗi xảy ra dưới 1 giây thường có nghĩa là do môi trường từ chối hoặc thiếu khả năng, trong khi lỗi từ 1-15 giây ám chỉ người dùng đã thấy và đóng hộp thoại. Trên các ứng dụng iOS và Android native, việc thiết lập preferImmediatelyAvailableCredentials trước khi gửi yêu cầu cung cấp cho bạn một tín hiệu "không có credentials" rõ ràng (mã 1005 trên iOS, GetCredentialRequest trên Android) trước khi giao diện người dùng hiển thị.
Trong các đợt triển khai passkey quy mô lớn được tối ưu hóa, trên 95% số lỗi WebAuthn được ghi lại đều là các trường hợp người dùng hủy theo dự kiến chứ không phải lỗi hệ thống. Việc theo dõi lượng error.name thô mà không tách biệt "người dùng đã đóng lời nhắc" khỏi các lỗi hỏng hóc thật sự sẽ thổi phồng các chỉ số đo lường lỗi và che đậy những sự cố đang ẩn chứa sau lượng NotAllowedError. Hãy phân chia số lượng dựa theo loại hoạt động, coi việc người dùng hủy giống như cách ta xử lý các tình huống đối với SecurityError, ConstraintError và DataError.
Mã 1005 trên iOS (NotInteractive) có nghĩa là không có passkey nào khả dụng trên thiết bị khi preferImmediatelyAvailableCredentials được đặt trên ASAuthorizationController, và không có giao diện người dùng nào được hiển thị cho người dùng. Đây là tín hiệu sạch "không có passkey tồn tại trên thiết bị này" mà các trình duyệt web không thể cung cấp do những hạn chế về quyền riêng tư. Luôn phân loại dựa trên mã số này, thay vì dựa trên localizedDescription, bởi vì thông báo của Apple được bản địa hóa sang hơn 30 ngôn ngữ và có thể thay đổi theo từng phiên bản hệ điều hành.
Trong quá trình conditional create, NotAllowedError, AbortError và InvalidStateError đều là các kết quả nằm trong dự kiến và nên được bỏ qua một cách lặng lẽ thay vì hiển thị lên như một lỗi. NotAllowedError biểu thị khả năng tự động điền không có sẵn hoặc trang đã mất tiêu điểm, trong khi InvalidStateError có nghĩa là passkey đã tồn tại trong nhà cung cấp. Trước khi thử gọi, hãy sử dụng getClientCapabilities() để xác nhận hỗ trợ của conditionalCreate và kiểm tra trạng thái hiển thị của tài liệu nhằm tránh làm tăng số lượng lỗi của bạn.
Hãy ghi nhận loại hoạt động (conditional UI, đăng nhập modal, tạo thủ công, conditional create hoặc nối thêm tự động), thời gian từ khi bắt đầu hoạt động đến khi xảy ra lỗi, phiên bản hệ điều hành, phiên bản trình duyệt, mẫu phần cứng, xem giao diện mã QR/hybrid có xuất hiện hay không và một ID tương quan để liên kết với nhật ký phía máy chủ. Các sự cố từ chối xác minh của máy chủ như không khớp challenge, chữ ký không hợp lệ và không tìm thấy credential nên được lưu lại dưới dạng các mã có cấu trúc rõ ràng, không được trộn lẫn với các tên DOMException ở phía máy khách. Nhờ kết hợp những tín hiệu này, bạn có thể phân loại phần lớn các lỗi vào các nhóm hành động rõ ràng mà không cần phải đoán mò.
Xem Corbado phù hợp thế nào với quá trình triển khai passkeys và stack xác thực hiện tại của bạn.
Khám phá Console
Bài viết liên quan
Mục lục