Bu kılavuzda, hem açık düğme tetikleyicileri hem de sorunsuz tarayıcı otomatik doldurma önerileri (koşullu kullanıcı arayüzü) aracılığıyla keşfedilebilir kimlik bilgilerini kullanarak geri gelen kullanıcı kimlik doğrulamasının nasıl uygulanacağı ayrıntılı olarak açıklanmaktadır.
Sunucu Tarafı
Seçenek oluşturma
Standartlara uygun şekilde incelenmiş bir kitaplık kullanarak WebAuthn istek parametreleri oluşturan bir uç nokta oluşturun.
- Önceden tanımlanmış RP kimliğini kullanma: Önceden tanımlanmış uygun RP kimliğini sabit bir dize olarak kullanın.
- Sorgulama oluşturma: Yüksek entropili, kriptografik olarak güvenli rastgele bir arabellek oluşturun, bunu kullanıcının oturumunda güvenli bir şekilde saklayın ve Base64URL olarak kodlayın.
- Keşfedilebilir kimlik bilgileri eşleme:
allowCredentialsiçin boş bir dizi[]belirtin. Bu, keşfedilebilir kimlik bilgileri ister. Yani kullanıcının önce kullanıcı adını girmesi gerekmez. Geçiş anahtarı sağlayıcı, mevcut hesapları gösterir. - Kullanıcı Doğrulama düzeyi:
userVerification: "preferred"(veya kurumsal uygunluk politikaları tarafından açıkça zorunlu kılınmışsa"required") olarak ayarlayın.- İstenen
userVerificationkısıtlama düzeyi, istemciden sorgu dizeleri aracılığıyla geri iletilmek yerine seçenekler uç noktasındaki sunucu oturumu kaydında kalıcı hale getirilmelidir. Bu sayede doğrulama uç noktası, istemci manipülasyonu riski olmadan katı eşleşme kısıtlamalarını güvenli bir şekilde uygulayabilir.
- İstenen
// Options generation example (discoverable flow)
const options = {
challenge: serverGeneratedBase64UrlChallenge, // High-entropy random challenge stored in session
rpId: "example.com",
allowCredentials: [], // Request discoverable passkeys
userVerification: "preferred",
};
// Persist expected UV level to user session
req.session.expectedUserVerification = "preferred";
Doğrulama uç noktası
Kullanıcının kimliğini doğrulamak için istemci tarafından döndürülen onayı güvenli bir şekilde doğrulayın:
- Oturum sorgulamasını doğrula: İstemci yanıtı ile oturumda depolanan beklenen sorgulama arasında katı sorgulama eşleşmesini zorunlu kılın.
- Kullanıcı görünümü tercihlerini zorunlu kılma:
- Oturumun
expectedUserVerificationdeğeri"preferred"iserequireUserVerification: falsedeğerini sunucu tarafı doğrulama kitaplığınıza ileterek UV içermeyen kimlik doğrulayıcılara (ör. kimlik doğrulayıcı ekran kilitleri devre dışı bırakılmışsa) izin verin. İstenirse"required"biyometrik/PIN girişini zorunlu kılın.
- Oturumun
- Temiz Sunucu Hatası 404: İstemci tarafından döndürülen kimlik bilgisi kimliği veritabanında bulunamazsa istemcinin Signal API'yi tetikleyebilmesi için açık bir HTTP
404hatası döndürün.
İstemci Tarafı Mantığı
HTML Formu Ek Açıklaması
Koşullu kullanıcı arayüzünden yerel olarak yararlanmak için kullanıcı adı ve şifre girişlerinize ek açıklama ekleyin. Otomatik tamamlama jetonları, webauthn spesifikasyon parametrelerini birleştirir ve otomatik odaklama, girişe odaklanıldığında tarayıcının otomatik doldurma pop-up'ını hemen tetikler.
<!-- Autocomplete tokens must contain webauthn space-separated -->
<form id="signin-form">
<input
type="text"
name="username"
autocomplete="username webauthn"
autofocus
data-testid="username-field"
/>
<input type="password" name="password" autocomplete="current-password" />
<button type="submit">Sign in</button>
</form>
Açık Düğme Akışı
Kullanıcı "Geçiş anahtarıyla oturum aç" düğmesini tıkladığında geçiş anahtarı kimlik doğrulamasını tetikleyin. Geçiş anahtarı istemini çağırmadan önce devam eden form otomatik doldurma (koşullu alma) çağrılarını iptal edin.
Koşullu Uyumlulaştırma Akışı (Form Otomatik Doldurma)
Kullanıcılar oturum açma alanlarına odaklandığında geçiş anahtarı kimlik doğrulamasını yerel olarak sunmak için sayfa yüklenirken form otomatik doldurma önerilerini etkinleştirin:
- Özellik algılama: Sayfa yüklendiğinde
PublicKeyCredential.getClientCapabilities()yöntemini çağırın veconditionalGetkullanılamıyorsa geçiş anahtarıyla oturum açma adımını atlayın. - Kod çözme seçenekleri: Alınan kimlik bilgisi JSON nesnesinin kodunu
PublicKeyCredential.parseRequestOptionsFromJSON()ile çözün. - Koşullu Get'i çağırın:
mediation: "conditional"ilenavigator.credentials.get()yöntemini çağırın ve birAbortControllersinyali iletin. Bu işlem, geçiş anahtarı iletişim kutusu oluşturmadan otomatik doldurma özelliğini sessizce kaydeder. - Try/Catch İstisna Ayrımı:
navigator.credentials.getçağrısını try/catch bloğuna sarmalayın:NotAllowedError: Kullanıcı, geçiş anahtarı giriş istemini iptal etti veya istemin süresi doldu.AbortError: Kimlik doğrulama isteği programatik olarak iptal edildi.
- Call Signal API: Sunucu doğrulama
fetch()çağrısını bir try/catch bloğuna sarmalayın:- Kullanıcının sorunun ne olduğunu anlaması için bir hata mesajı gösterin.
signalUnknownCredential()yöntemini YALNIZCA sunucu açıkça HTTP durumu404(Kimlik bilgisi bulunamadı) ile yanıt verdiğinde ve kullanıcının kimliği doğrulanmadığında çağırın.signalUnknownCredential()yöntemine iletilencredentialIdparametresi, ham ArrayBuffer nesnesicredential.rawIdDEĞİL, Base64URL ile kodlanmış kimlik bilgisi kimliği dizesi (ör.encoded.id) OLMALIDIR.
- Yanıtı kodlama: Doğrulama için sunucuya göndermeden önce
AuthenticatorAssertionResponsekimlik bilgisini.toJSON()ile kodlayın.
// optionsFetch and loginVerifyFetch are app-defined HTTP methods
import { optionsFetch, loginVerifyFetch } from "./api.js";
let autofillAbortController = new AbortController();
async function initializeConditionalAutofill() {
// Feature detect Conditional Get autofill support
const capabilities = await PublicKeyCredential.getClientCapabilities();
if (capabilities.conditionalGet === true) {
const loginOptionsJSON = await optionsFetch();
const publicKey =
PublicKeyCredential.parseRequestOptionsFromJSON(loginOptionsJSON);
try {
// Initiate Conditional UI form autofill suggestions
const credential = await navigator.credentials.get({
publicKey,
signal: autofillAbortController.signal,
mediation: "conditional",
});
// Segregated verification fetch
const encoded = credential.toJSON();
const response = await loginVerifyFetch(encoded);
if (!response.ok && response.status === 404) {
// Note: this code path runs pre-authentication, satisfying the unauth precondition
if (PublicKeyCredential.signalUnknownCredential) {
await PublicKeyCredential.signalUnknownCredential({
rpId, // RP ID must match the one defined on the server
credentialId: encoded.id,
});
}
}
} catch (err) {
// Silently swallow expected client WebAuthn exceptions
if (["NotAllowedError", "AbortError"].includes(err.name)) {
return;
}
console.error("Unexpected conditional get error:", err);
}
}
}
async function triggerButtonAuthentication() {
// Abort any pending Conditional Get call to prevent passkey prompt collisions
autofillAbortController.abort();
autofillAbortController = new AbortController(); // Reset controller for next triggers
const loginOptionsJSON = await optionsFetch();
const publicKey =
PublicKeyCredential.parseRequestOptionsFromJSON(loginOptionsJSON);
let credential;
try {
// Passkey explicit prompt trigger
credential = await navigator.credentials.get({
publicKey,
signal: autofillAbortController.signal,
});
} catch (err) {
if (err.name === "NotAllowedError") {
console.log("User cancelled passkey login.");
} else if (err.name === "AbortError") {
console.log("The authentication operation was aborted.");
}
// Re-arm Conditional autofill Suggestions after cancelled explicit button prompts
initializeConditionalAutofill();
return; // Safe exit
}
// Segregated verification try/catch (HTTP 404 trigger)
const encoded = credential.toJSON();
try {
const response = await loginVerifyFetch(encoded);
if (!response.ok && response.status === 404) {
// Note: this code path runs pre-authentication, satisfying the unauth precondition
await PublicKeyCredential.signalUnknownCredential({
rpId, // RP ID must match the one defined on the server
credentialId: encoded.id, // Base64URL-encoded credential ID
});
}
} catch (serverErr) {
console.error("Verification request error:", serverErr);
}
}
// Trigger Conditional Get on load
window.addEventListener("DOMContentLoaded", initializeConditionalAutofill);
Yedek Stratejiler
Geçiş anahtarı özelliği algılama yedeği
"webauthn-polyfills"i her zaman yükleyin ve bağlama aktarın.
PublicKeyCredential desteklendiği sürece PublicKeyCredential.getClientCapabilities de desteklenir.
import 'webauthn-polyfills';
Signal API Senkronizasyonu Yedeklemesi
WebAuthn Signal API (webauthn-signals), şifre yöneticilerini sunucu kimlik bilgisi durumuyla senkronize tutmak için kullanılan aşamalı bir optimizasyondur.
- Yedek Deneyim:
if (PublicKeyCredential.signalUnknownCredential)üzerinden erişim kısıtlaması uygulanır. Desteklenmiyorsa arka plan doğrulama senkronizasyonu, tarayıcı istisnaları oluşturmadan sorunsuz bir şekilde atlanır.
Kolay JSON Serileştirme Yedeklemesi
"webauthn-polyfills"i her zaman yükleyin ve bağlama aktarın.
PublicKeyCredential desteklendiği sürece PublicKeyCredential.parseRequestOptionsFromJSON ve PublicKeyCredential.prototype.toJSON de desteklenir.
import 'webauthn-polyfills';