Meskipun kredensial FIDO seperti kunci sandi bertujuan untuk menggantikan sandi, sebagian besar dari kredensial tersebut juga dapat membuat pengguna tidak perlu mengetik nama pengguna. Hal ini memungkinkan pengguna melakukan autentikasi dengan memilih akun dari daftar kunci sandi yang mereka miliki untuk situs saat ini.
Kunci keamanan versi sebelumnya dirancang sebagai metode autentikasi 2 langkah, dan memerlukan ID kredensial potensial, sehingga memerlukan entri nama pengguna. Kredensial yang dapat ditemukan 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 dibuat sebagai kunci sandi (kredensial yang dapat ditemukan), tentukan residentKey
dan requireResidentKey
saat kredensial dibuat.
Pihak tepercaya (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 salah satunya, nilai user.id
akan disertakan dalam tanda tangan yang dihasilkan. Server kemudian dapat menggunakan ID kredensial tersebut atau
ID kredensial yang ditampilkan untuk mencari akun, bukan nama pengguna yang diketik.
UI pemilih akun, seperti yang telah dibahas sebelumnya, tidak pernah menampilkan kredensial yang tidak dapat ditemukan.
requireResidentKey
dan residentKey
Untuk membuat kunci sandi, tentukan authenticatorSelection.residentKey
dan authenticatorSelection.requireResidentKey
di 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, spesifikasi versi lama. Tetapkan ke
true
jikaresidentKey
adalah'required'
, jika tidak, tetapkan kefalse
.
allowCredentials
RP dapat menggunakan allowCredentials
di navigator.credentials.get()
untuk mengontrol pengalaman autentikasi kunci sandi. Biasanya ada tiga jenis pengalaman autentikasi kunci sandi:
Tampilkan pemilih akun modal
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. Hal ini cocok untuk alur autentikasi kunci sandi yang dimulai dengan menekan tombol khusus untuk autentikasi kunci sandi.
Untuk mencapai 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;
// ...
}
Menampilkan 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 tetap akan muncul dan akan menawarkan pengguna untuk menampilkan kunci sandi dari perangkat lain. Saat mentransisikan pengguna ke kunci sandi, Anda mungkin ingin menghindari UI tersebut untuk pengguna yang belum menyiapkannya.
Sebagai gantinya, pemilihan kunci sandi dapat digabungkan ke perintah isi otomatis untuk kolom dalam formulir login biasa, bersama dengan nama pengguna dan sandi yang disimpan. Dengan cara ini, pengguna dengan kunci sandi dapat "mengisi" formulir login dengan memilih kunci sandinya, pengguna dengan pasangan nama pengguna/sandi tersimpan dapat memilihnya, dan pengguna yang tidak memiliki keduanya masih dapat mengetik nama pengguna dan sandinya.
Pengalaman pengguna ini sangat ideal ketika RP sedang dalam proses migrasi dengan berbagai penggunaan sandi dan kunci sandi.
Untuk mencapai pengalaman pengguna ini, selain meneruskan array kosong ke properti allowCredentials
atau menghilangkan parameter, tentukan mediation: 'conditional'
di 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, kunci sandi yang tersedia akan disertakan dalam opsi isi otomatis. Jika pengguna memilih salah satunya, mereka akan melalui verifikasi buka kunci perangkat reguler, dan baru kemudian promise yang ditampilkan oleh .get()
akan di-resolve dengan 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 menampilkan bentuk pemilih akun apa pun. Hal ini dapat dilakukan dengan meneruskan daftar ID kredensial dalam parameter allowCredentials
.
Dalam hal ini, jika salah satu kredensial yang disebutkan tersedia secara lokal, pengguna akan langsung diminta untuk membuka kunci perangkat. Jika tidak, pengguna akan diminta untuk menunjukkan perangkat lain (ponsel atau kunci keamanan) yang memiliki kredensial yang valid.
Untuk mendapatkan pengalaman pengguna ini, berikan daftar ID kredensial untuk pengguna yang login. RP harus dapat membuat 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 telah diperoleh RP pada pendaftaran kunci sandi.type
: Kolom ini biasanya berupa'public-key'
.transports
: Petunjuk transpor yang didukung oleh perangkat yang menyimpan kredensial ini, yang digunakan oleh browser untuk mengoptimalkan UI yang meminta pengguna untuk mempresentasikan perangkat eksternal. Daftar ini, jika disediakan, harus berisi hasil pemanggilangetTransports()
selama pendaftaran setiap kredensial.
Ringkasan
Kredensial yang dapat ditemukan membuat pengalaman login kunci sandi jauh lebih mudah digunakan karena pengguna tidak perlu memasukkan nama pengguna. Dengan kombinasi residentKey
, requireResidentKey
, dan allowCredentials
, RP dapat mencapai 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 kunci sandi yang canggih yang akan dirasakan pengguna sebagai lancar dan lebih cenderung untuk berinteraksi.