Pembuatan Bersyarat Kunci Sandi (Promosi Pasca-Login)

Panduan ini menjelaskan cara mendaftarkan kunci sandi secara otomatis dan otomatis untuk pengguna segera setelah login berbasis sandi berhasil, sehingga meminimalkan hambatan dan meningkatkan adopsi kunci sandi.

Momen Pemicu yang Tepat

Pembuatan kunci sandi otomatis (juga dikenal sebagai Pembuatan Bersyarat atau promosi pasca-login otomatis) HARUS dipicu hanya segera setelah login penuh yang berhasil dan melibatkan sandi.

  • Jangan mencoba pembuatan bersyarat untuk alur tanpa sandi (misalnya, magic link, OTP SMS, atau penggabungan identitas).
  • Jika autentikasi multi-faktor diperlukan, Anda HARUS menunggu hingga semua faktor berhasil sebelum memulai pembuatan bersyarat.
  • Pastikan sesi pengguna yang valid dan terautentikasi aktif sebelum membuat permintaan ke endpoint pembuatan.

Langkah-Langkah Penerapan

1. Membatalkan Tindakan Isi Otomatis Sebelumnya

Jika halaman login menggunakan isi otomatis formulir (UI Bersyarat/Get), panggilan get kredensial aktif harus dibatalkan untuk mencegah konflik browser.

  • Panggil abortController.abort() pada AbortController yang dilampirkan ke permintaan isi otomatis navigator.credentials.get() yang tertunda sebelum memanggil navigator.credentials.create().

2. Deteksi Fitur

Tentukan apakah Pembuatan Bersyarat tersedia dengan memeriksa conditionalCreate dengan PublicKeyCredential.getClientCapabilities().

const capabilities = await PublicKeyCredential.getClientCapabilities();
if (capabilities.conditionalCreate) {
  // Conditional create is available
}

3. Membuat kunci sandi dengan Pembuatan Bersyarat

  • Teruskan mediation: 'conditional' dalam opsi navigator.credentials.create(). Hal ini memberi sinyal kepada browser untuk menangani alur pembuatan kunci sandi secara otomatis di latar belakang atau secara kontekstual tanpa menampilkan dialog modal yang mengganggu.
  • Isi excludeCredentials dengan ID kredensial kunci sandi pengguna yang ada untuk menghindari pendaftaran kunci duplikat.

4. Penanganan Error Senyap

  • Gabungkan dialog pembuatan kunci sandi (navigator.credentials.create) dalam blok try/catch. Anda HARUS menangkap dan mengabaikan pengecualian umum yang ditampilkan kepada pengguna (InvalidStateError, NotAllowedError, AbortError) tanpa merender UI error apa pun kepada pengguna.

5. Verifikasi Kehadiran Pengguna Sisi Server

  • Endpoint verifikasi sisi server HARUS melonggarkan persyaratan Kehadiran Pengguna (UP) (requireUserPresence: false) HANYA saat memverifikasi kredensial yang dihasilkan oleh pemicu pembuatan bersyarat. Verifikasi kehadiran yang ketat harus tetap aktif untuk pembuatan eksplisit standar.

6. Menangani Verifikasi Server yang Gagal dengan baik

  • Jika navigator.credentials.create() berhasil, tetapi pengambilan verifikasi server menampilkan respons yang buruk (misalnya, verifikasi tanda tangan gagal), panggil PublicKeyCredential.signalUnknownCredential() untuk mencegah kredensial tanpa induk tetap berada di penyedia kunci sandi.

Contoh Kode

// optionsFetch and registerVerifyFetch are app-defined server endpoint requests
import { optionsFetch, registerVerifyFetch } from './api.js';

async function triggerConditionalCreate(loginAbortController) {
  const capabilities = await PublicKeyCredential.getClientCapabilities();
  if (capabilities.conditionalCreate !== true) {
    return; // Platform does not support conditional creation
  }

  // 1. Abort any active autofill conditional-get controllers to clear the WebAuthn pipeline
  loginAbortController.abort();

  // 2. Fetch creation options signaling the backend that this is a conditional request
  const creationOptionsJSON = await optionsFetch({ conditional: true });
  const publicKey = PublicKeyCredential.parseCreationOptionsFromJSON(creationOptionsJSON);

  let credential;
  try {
    // 3. Invoke silent credentials creation prompt
    credential = await navigator.credentials.create({ 
      publicKey,
      mediation: 'conditional' // Silent background creation mediation
    });
  } catch (e) {
    // 4. Silently swallow common WebAuthn browser exceptions
    if (['InvalidStateError', 'NotAllowedError', 'AbortError'].includes(e.name)) {
      return; 
    }
    console.error('Unexpected conditional create error:', e);
    return;
  }

  // 5. Server verification step using dedicated Try/Catch block
  let encodedResponse = credential.toJSON();
  try {
    const response = await registerVerifyFetch(encodedResponse);
    if (!response.ok) {
      // If the server verification fails, clean up using Signal API
      if (PublicKeyCredential.signalUnknownCredential) {
        await PublicKeyCredential.signalUnknownCredential({
          rpId, // RP ID must match the one defined on the server
          credentialId: encodedResponse.id
        });
      }
    }
  } catch (serverErr) {
    console.error('Verification network failure:', serverErr);
    if (PublicKeyCredential.signalUnknownCredential) {
      await PublicKeyCredential.signalUnknownCredential({
        rpId, // RP ID must match the one defined on the server
        credentialId: encodedResponse.id
      });
    }
  }
}

Strategi Penggantian

Penggantian deteksi fitur kunci sandi

Selalu instal 'webauthn-polyfills' dan impor dalam konteks. Pertimbangkan bahwa selama PublicKeyCredential didukung, PublicKeyCredential.getClientCapabilities juga didukung.

import 'webauthn-polyfills';

Penggantian Sinkronisasi Signal API

WebAuthn Signal API (webauthn-signals) adalah pengoptimalan progresif yang digunakan untuk menjaga pengelola sandi tetap sinkron dengan status kredensial server.

  • Pengalaman Pengganti: Dibatasi melalui if (PublicKeyCredential.signalUnknownCredential). Jika tidak didukung, sinkronisasi verifikasi latar belakang akan dilewati dengan baik tanpa menampilkan pengecualian browser.

Penggantian Serialisasi JSON yang Mudah

Selalu instal 'webauthn-polyfills' dan impor dalam konteks. Pertimbangkan bahwa selama PublicKeyCredential didukung, PublicKeyCredential.parseCreationOptionsFromJSON dan PublicKeyCredential.prototype.toJSON juga didukung.

import 'webauthn-polyfills';