Embora as credenciais do 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 eles 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, exigindo a entrada 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
quando a credencial for criada.
As partes confiáveis (RPs) podem usar credenciais detectáveis omitindo
allowCredentials
durante a autenticação de chave de acesso. Nesses casos,
o navegador ou 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 um, 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 da seguinte maneira.
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'
: é necessário criar uma credencial detectável. Se não for possível criar,NotSupportedError
será retornado.'preferred'
: o RP prefere criar uma credencial detectável, mas aceita uma credencial não detectável.'discouraged'
: o RP 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 Nível 1, uma versão mais antiga da especificação. Defina como
true
seresidentKey
for'required'
. Caso contrário, defina comofalse
.
allowCredentials
Os RPs podem usar allowCredentials
em navigator.credentials.get()
para controlar a experiência de autenticação de chave de acesso. Geralmente, há três tipos de experiência de autenticação de chave de acesso:
- Mostrar um seletor de conta modal
- Mostrar o preenchimento automático de um formulário de chave de acesso
- Reautenticação
Mostrar um seletor de conta modal
Com credenciais detectáveis, os RPs podem mostrar um seletor de conta modal para que o usuário selecione 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 pressionando um botão dedicado a essa autenticação.
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 o preenchimento automático de um formulário de chave de acesso
O seletor de conta modal descrito acima funciona bem se a maioria dos usuários usar chaves de acesso e elas estiverem 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 outro dispositivo. Durante a transição dos usuários para chaves de acesso, evite essa interface para usuários que não configuraram uma.
Em vez disso, a seleção de uma chave de acesso pode ser incluída em 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 selecionar esses pares, e os usuários sem nenhum deles ainda podem digitar o nome de usuário e a senha.
Essa experiência do usuário é ideal quando o RP está em migração com um uso misto de senhas e chaves de acesso.
Para conseguir 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 username
HTML com autocomplete="username webauthn"
ou um campo de entrada password
com autocomplete="password webauthn"
.
A chamada para navigator.credentials.get()
não vai fazer com que nenhuma interface seja mostrada, mas se o usuário focar o campo de entrada com anotação, todas as chaves de acesso disponíveis serão incluídas nas opções de preenchimento automático. Se o usuário selecionar um, 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="username webauthn" ...>
Aprenda a criar essa experiência do usuário em Fazer login com uma chave de acesso usando o preenchimento automático de formulários e no 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 reautorização, o identificador do usuário já é conhecido. Nesse caso, gostaríamos de usar uma chave de acesso sem que o navegador ou o SO mostre qualquer forma de seletor de conta. Para fazer isso, transmita uma lista de IDs de credencial no parâmetro allowCredentials
.
Nesse caso, se alguma das credenciais nomeadas estiver disponível localmente, o usuário vai receber uma solicitação para desbloquear o dispositivo imediatamente. Caso contrário, o usuário vai precisar apresentar outro dispositivo (um smartphone ou uma chave de segurança) com uma credencial válida.
Para oferecer essa experiência, forneça uma lista de IDs de credencial para o usuário que está fazendo login. O RP precisa ser capaz de fazer consultas, 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 o RP recebeu no registro da chave de acesso.type
: esse campo geralmente é'public-key'
.transports
: uma dica de transportes aceitos pelo dispositivo que tem 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 para o usuário, permitindo que ele pule a etapa de entrada de nome de usuário. Com a combinação de residentKey
, requireResidentKey
e allowCredentials
, os RPs podem ter experiências de login que:
- Mostrar um seletor de contas modal.
- Mostrar o preenchimento automático de um formulário de chave de acesso.
- Reautorização.
Use 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 simples e com maior probabilidade de interação.