Mempelajari lebih dalam tentang kredensial yang mudah ditemukan

Meskipun kredensial FIDO seperti kunci sandi bertujuan untuk mengganti sandi, sebagian besar kredensial tersebut juga dapat membebaskan pengguna agar tidak mengetikkan nama pengguna. Langkah ini memungkinkan pengguna melakukan autentikasi dengan memilih akun dari daftar kunci sandi yang mereka miliki untuk situs saat ini.

Versi kunci keamanan sebelumnya dirancang sebagai metode autentikasi 2 langkah, dan memerlukan ID kredensial potensial, sehingga memerlukan entri nama pengguna. Kredensial yang dapat ditemukan oleh kunci keamanan tanpa mengetahui ID-nya disebut kredensial yang dapat ditemukan. Sebagian besar kredensial FIDO yang dibuat saat ini adalah kredensial yang dapat ditemukan; terutama kunci sandi yang disimpan di pengelola sandi atau di kunci keamanan modern.

Untuk memastikan kredensial Anda dapat ditemukan, tentukan residentKey dan requireResidentKey saat kunci sandi dibuat.

Pihak pengandal (RP) dapat menggunakan kredensial yang dapat ditemukan dengan menghapus allowCredentials selama autentikasi kunci sandi. Dalam kasus ini, browser atau sistem akan menampilkan daftar kunci sandi yang tersedia kepada pengguna, yang diidentifikasi oleh properti user.name yang ditetapkan pada waktu pembuatan. Jika pengguna memilih satu, nilai user.id akan disertakan dalam tanda tangan yang dihasilkan. Selanjutnya, server dapat menggunakannya atau ID kredensial yang ditampilkan untuk mencari akun, bukan nama pengguna yang diketik.

UI pemilih akun, seperti yang dibahas sebelumnya, tidak pernah menampilkan kredensial yang tidak dapat ditemukan.

requireResidentKey dan residentKey

Untuk membuat kredensial yang dapat ditemukan, tentukan authenticatorSelection.residentKey dan authenticatorSelection.requireResidentKey pada navigator.credentials.create() dengan nilai yang ditunjukkan sebagai berikut.

async function register () {
  // ...

  const publicKeyCredentialCreationOptions = {
    // ...
    authenticatorSelection: {
      authenticatorAttachment: 'platform',
      residentKey: 'required',
      requireResidentKey: true,
    }
  };

  const credential = await navigator.credentials.create({
    publicKey: publicKeyCredentialCreationOptions
  });

  // This does not run until the user selects a passkey.
  const credential = {};
  credential.id = cred.id;
  credential.rawId = cred.id; // Pass a Base64URL encoded ID string.
  credential.type = cred.type;

  // ...
}

residentKey:

  • 'required': Kredensial yang dapat ditemukan harus dibuat. Jika tidak dapat dibuat, NotSupportedError akan ditampilkan.
  • 'preferred': RP lebih memilih membuat kredensial yang dapat ditemukan, tetapi menerima kredensial yang tidak dapat ditemukan.
  • 'discouraged': RP lebih memilih membuat kredensial yang tidak dapat ditemukan, tetapi menerima kredensial yang dapat ditemukan.

requireResidentKey:

  • Properti ini dipertahankan untuk kompatibilitas mundur dari WebAuthn Level 1, versi lama spesifikasi. Tetapkan ke true jika residentKey adalah 'required'. Jika tidak, tetapkan ke false.

allowCredentials

RP dapat menggunakan allowCredentials di navigator.credentials.get() untuk mengontrol pengalaman autentikasi kunci sandi. Biasanya ada tiga jenis pengalaman autentikasi kunci sandi:

Dengan kredensial yang dapat ditemukan, RP dapat menampilkan pemilih akun modal bagi pengguna untuk memilih akun yang akan digunakan untuk login, diikuti dengan verifikasi pengguna. Ini sesuai untuk alur autentikasi kunci sandi yang dimulai dengan menekan tombol khusus untuk autentikasi kunci sandi.

Untuk mendapatkan pengalaman pengguna ini, hapus atau teruskan array kosong ke parameter allowCredentials di navigator.credentials.get().

async function authenticate() {
  // ...

  const publicKeyCredentialRequestOptions = {
    // Server generated challenge:
    challenge: ****,
    // The same RP ID as used during registration:
    rpId: 'example.com',
    // You can omit `allowCredentials` as well:
    allowCredentials: []
  };

  const credential = await navigator.credentials.get({
    publicKey: publicKeyCredentialRequestOptions,
    signal: abortController.signal
  });

  // This does not run until the user selects a passkey.
  const credential = {};
  credential.id = cred.id;
  credential.rawId = cred.id; // Pass a Base64URL encoded ID string.
  credential.type = cred.type;
  
  // ...
}

Tampilkan isi otomatis formulir kunci sandi

Pemilih akun modal yang dijelaskan di atas berfungsi dengan baik jika sebagian besar pengguna menggunakan kunci sandi dan menyediakannya di perangkat lokal. Untuk pengguna yang tidak memiliki kunci sandi lokal, dialog modal akan tetap muncul dan akan menawarkan kepada pengguna untuk menyajikan kunci sandi dari perangkat lain. Saat mentransisikan pengguna ke kunci sandi, Anda dapat menghindari UI tersebut untuk pengguna yang belum menyiapkannya.

Sebagai gantinya, pilihan kunci sandi dapat ditampilkan menjadi perintah isi otomatis untuk kolom dalam formulir login tradisional, beserta nama pengguna dan sandi yang tersimpan. Dengan cara ini, pengguna yang memiliki kunci sandi dapat "mengisi" formulir login dengan memilih kunci sandinya, pengguna dengan pasangan nama pengguna/sandi tersimpan dapat memilihnya, dan pengguna yang tidak memiliki kunci sandi tetap dapat mengetikkan nama pengguna dan sandi mereka.

Pengalaman pengguna ini ideal saat RP sedang dalam proses migrasi dengan beragam penggunaan sandi dan kunci sandi.

Untuk mendapatkan pengalaman pengguna ini, selain meneruskan array kosong ke properti allowCredentials atau menghapus parameter, tentukan mediation: 'conditional' pada navigator.credentials.get() dan anotasikan kolom input username HTML dengan autocomplete="username webauthn" atau kolom input password dengan autocomplete="password webauthn".

Panggilan ke navigator.credentials.get() tidak akan menyebabkan UI ditampilkan, tetapi jika pengguna memfokuskan kolom input yang dianotasi, semua kunci sandi yang tersedia akan disertakan dalam opsi isi otomatis. Jika pengguna memilih satu, mereka akan melalui verifikasi buka kunci perangkat reguler, dan hanya setelah itu, promise yang ditampilkan oleh .get() akan memberikan hasil. Jika pengguna tidak memilih kunci sandi, promise tidak akan pernah diselesaikan.

async function authenticate() {
  // ...

  const publicKeyCredentialRequestOptions = {
    // Server generated challenge:
    challenge: ****,
    // The same RP ID as used during registration:
    rpId: 'example.com',
    // You can omit `allowCredentials` as well:
    allowCredentials: []
  };

  const cred = await navigator.credentials.get({
    publicKey: publicKeyCredentialRequestOptions,
    signal: abortController.signal,
    // Specify 'conditional' to activate conditional UI
    mediation: 'conditional'
  });

  // This does not run until the user selects a passkey.
  const credential = {};
  credential.id = cred.id;
  credential.rawId = cred.id; // Pass a Base64URL encoded ID string.
  credential.type = cred.type;
  
  // ...
}
<input type="text" name="username" autocomplete="username webauthn" ...>

Anda dapat mempelajari cara membuat pengalaman pengguna ini di Login dengan kunci sandi melalui isi otomatis formulir, serta codelab Mengimplementasikan kunci sandi dengan isi otomatis formulir di aplikasi web.

Autentikasi ulang

Dalam beberapa kasus, seperti saat menggunakan kunci sandi untuk autentikasi ulang, ID pengguna sudah diketahui. Dalam hal ini, kita ingin menggunakan kunci sandi tanpa browser atau OS yang menampilkan bentuk pemilih akun apa pun. Hal ini dapat dilakukan dengan meneruskan daftar ID kredensial di parameter allowCredentials.

Dalam hal ini, jika salah satu kredensial yang dinamai tersedia secara lokal, pengguna akan langsung diminta untuk membuka kunci perangkat. Jika tidak, pengguna akan diminta untuk memberikan perangkat lain (ponsel atau kunci keamanan) yang menyimpan kredensial yang valid.

Untuk mencapai pengalaman pengguna ini, berikan daftar ID kredensial untuk pengguna yang login. RP harus dapat melakukan kueri karena pengguna sudah diketahui. Berikan ID kredensial sebagai objek PublicKeyCredentialDescriptor di properti allowCredentials di navigator.credentials.get().

async function authenticate() {
  // ...

  const publicKeyCredentialRequestOptions = {
    // Server generated challenge:
    challenge: ****,
    // The same RP ID as used during registration:
    rpId: 'example.com',
    // Provide a list of PublicKeyCredentialDescriptors:
    allowCredentials: [{
      id: ****,
      type: 'public-key',
      transports: [
        'internal',
        'hybrid'
      ]
    }, {
      id: ****,
      type: 'public-key',
      transports: [
        'internal',
        'hybrid'
      ]
    }, ...]
  };

  const credential = await navigator.credentials.get({
    publicKey: publicKeyCredentialRequestOptions,
    signal: abortController.signal
  });

  // This does not run until the user selects a passkey.
  const credential = {};
  credential.id = cred.id;
  credential.rawId = cred.id; // Pass a Base64URL encoded ID string.
  credential.type = cred.type;
  
  // ...
}

Objek PublicKeyCredentialDescriptor terdiri dari:

  • id: ID kredensial kunci publik yang diperoleh RP saat pendaftaran kunci sandi.
  • type: Kolom ini biasanya berisi 'public-key'.
  • transports: Petunjuk transport yang didukung oleh perangkat yang menyimpan kredensial ini, digunakan oleh browser untuk mengoptimalkan UI yang meminta pengguna untuk menampilkan perangkat eksternal. Daftar ini, jika disediakan, harus berisi hasil pemanggilan getTransports() selama pendaftaran setiap kredensial.

Ringkasan

Kredensial yang dapat ditemukan membuat pengalaman login kunci sandi jauh lebih mudah digunakan dengan memungkinkan pengguna melewati proses memasukkan nama pengguna. Dengan kombinasi residentKey, requireResidentKey, dan allowCredentials, RP dapat memperoleh pengalaman login yang:

  • Menampilkan pemilih akun modal.
  • Menampilkan isi otomatis formulir kunci sandi.
  • Autentikasi ulang.

Gunakan kredensial yang dapat ditemukan dengan bijak. Dengan demikian, Anda dapat mendesain pengalaman login dengan kunci sandi yang canggih, yang akan lancar dan lebih mungkin digunakan oleh pengguna.