Embora as credenciais FIDO, como chaves de acesso, tenham como objetivo substituir as senhas, a maioria delas também pode dispensar o usuário de digitar um nome de usuário. Isso permite que os usuários se autentiquem selecionando uma conta em uma lista de chaves de acesso que têm para o site atual.
As versões anteriores das chaves de segurança foram projetadas como métodos de autenticação em duas etapas e exigiam os IDs de possíveis credenciais, o que exigia a inserção de um nome de usuário. As credenciais que uma chave de segurança pode encontrar sem saber os IDs são chamadas de credenciais detectáveis. A maioria das credenciais FIDO criadas hoje são detectáveis, principalmente as chaves de acesso armazenadas em um gerenciador de senhas ou em uma chave de segurança moderna.
Para garantir que suas credenciais sejam criadas como chaves de acesso (credenciais detectáveis), especifique residentKey e requireResidentKey ao criar a credencial.
As partes confiáveis (RPs, na sigla em inglês) podem usar credenciais detectáveis omitindo
allowCredentials durante a autenticação de chave de acesso. Nesses casos,
o navegador ou o sistema mostra ao usuário uma lista de chaves de acesso disponíveis, identificadas pela
propriedade user.name definida no momento da criação. Se o usuário selecionar uma, o valor user.id
será incluído na assinatura resultante. O servidor pode usar esse ID ou o ID de credencial retornado para procurar a conta em vez de um nome de usuário digitado.
As interfaces do seletor de contas, como as discutidas anteriormente, nunca mostram credenciais não detectáveis.
requireResidentKey e residentKey
Para criar uma chave de acesso, especifique authenticatorSelection.residentKey e authenticatorSelection.requireResidentKey em navigator.credentials.create() com os valores indicados abaixo.
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': uma credencial detectável precisa ser criada. Se não for possível criar,NotSupportedErrorserá retornado.'preferred': a parte confiável prefere criar uma credencial detectável, mas aceita uma não detectável.'discouraged': a parte confiável prefere criar uma credencial não detectável, mas aceita uma detectável.
requireResidentKey:
- Essa propriedade é mantida para compatibilidade com versões anteriores do WebAuthn Level 1, uma versão mais antiga da especificação. Defina como
trueseresidentKeyfor'required'. Caso contrário, defina comofalse.
allowCredentials
As partes confiáveis podem usar allowCredentials em navigator.credentials.get() para controlar a experiência de autenticação da chave de acesso. Normalmente, há três tipos de experiências de autenticação com chave de acesso:
- Mostrar um seletor de conta modal
- Mostrar um preenchimento automático de formulário de chave de acesso
- Reautenticação
Mostrar um seletor de conta modal
Com as credenciais detectáveis, as partes confiáveis podem mostrar um seletor de contas modal para o usuário selecionar uma conta para fazer login, seguido pela verificação do usuário. Isso é adequado para o fluxo de autenticação de chave de acesso iniciado ao pressionar um botão dedicado à autenticação de chave de acesso.
Para conseguir essa experiência do usuário, omita ou transmita uma matriz vazia para o parâmetro allowCredentials em 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;
// ...
}
Mostrar um preenchimento automático de formulário de chave de acesso
O seletor de contas modal descrito acima funciona bem se a maioria dos usuários usa chaves de acesso e as tem disponíveis no dispositivo local. Para um usuário que não tem chaves de acesso locais, a caixa de diálogo modal ainda aparece e oferece a opção de apresentar uma chave de acesso de outro dispositivo. Durante a transição dos usuários para as chaves de acesso, talvez você queira evitar essa interface para os usuários que ainda não configuraram uma.
Em vez disso, a seleção de uma chave de acesso pode ser integrada às solicitações de preenchimento automático para os campos em um formulário de login tradicional, junto com nomes de usuário e senhas salvos. Dessa forma, um usuário com chaves de acesso pode "preencher" o formulário de login selecionando a chave de acesso, os usuários com pares de nome de usuário/senha salvos podem selecioná-los e os usuários que não têm nenhum dos dois ainda podem digitar o nome de usuário e a senha.
Essa experiência do usuário é ideal quando a parte confiável está em uma migração com uso misto de senhas e chaves de acesso.
Para alcançar essa experiência do usuário, além de transmitir uma matriz vazia para a propriedade allowCredentials ou omitir o parâmetro, especifique mediation: 'conditional' em navigator.credentials.get() e anote um campo de entrada HTML username com autocomplete="username webauthn" ou um campo de entrada password com autocomplete="password webauthn".
A chamada para navigator.credentials.get() não faz com que nenhuma interface seja mostrada, mas, se o usuário focar no campo de entrada anotado, todas as chaves de acesso disponíveis serão incluídas nas opções de preenchimento automático. Se o usuário selecionar uma, ele vai passar pela verificação normal de desbloqueio do dispositivo e, só então, a promessa retornada por .get() será resolvida com um resultado. Se o usuário não selecionar uma chave de acesso, a promessa nunca será resolvida.
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=&qu>ot;username webauthn" ...
Para saber como criar essa experiência do usuário, consulte Fazer login com uma chave de acesso usando o preenchimento automático de formulários e o codelab Implementar chaves de acesso com o preenchimento automático de formulários em um app da Web.
Reautenticação
Em alguns casos, como ao usar chaves de acesso para reautenticação, o identificador do usuário já é conhecido. Nesse caso, queremos usar uma chave de acesso sem que o navegador ou o SO mostre qualquer forma de seletor de conta. Para isso, transmita uma lista de IDs de credenciais no parâmetro allowCredentials.
Nesse caso, se alguma das credenciais nomeadas estiver disponível localmente, o usuário vai precisar desbloquear o dispositivo imediatamente. Caso contrário, o usuário precisa apresentar outro dispositivo (um smartphone ou uma chave de segurança) que tenha uma credencial válida.
Para conseguir essa experiência do usuário, forneça uma lista de IDs de credenciais para o usuário que está fazendo login. A parte confiável precisa ser capaz de consultá-las porque o usuário já é conhecido. Forneça IDs de credencial como objetos PublicKeyCredentialDescriptor na propriedade allowCredentials em 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;
// ...
}
Um objeto PublicKeyCredentialDescriptor consiste em:
id: um ID da credencial de chave pública que a parte confiável recebeu no registro da chave de acesso.type: esse campo geralmente é'public-key'.transports: uma dica de transportes compatíveis com o dispositivo que contém essa credencial, usada pelos navegadores para otimizar a interface que pede ao usuário para apresentar um dispositivo externo. Essa lista, se fornecida, precisa conter o resultado da chamada degetTransports()durante o registro de cada credencial.
Resumo
As credenciais detectáveis tornam a experiência de login com chave de acesso muito mais fácil, permitindo que os usuários pulem a etapa de inserir um nome de usuário. Com a combinação de residentKey, requireResidentKey e allowCredentials, as partes confiáveis podem oferecer experiências de login que:
- Mostra um seletor de conta modal.
- Mostrar um preenchimento automático de formulário de chave de acesso.
- Reautenticação.
Use as credenciais detectáveis com sabedoria. Assim, você pode criar experiências de login com chave de acesso sofisticadas que os usuários vão achar fáceis de usar e com as quais terão mais chances de interagir.