As chaves de acesso tornam as contas dos usuários mais seguras, simples e fáceis de usar.
O uso de chaves de acesso em vez de senhas é uma ótima maneira de tornar as contas dos usuários mais seguras, simples, fáceis de usar e sem senha. Com uma chave de acesso, o usuário pode fazer login em um site ou app usando apenas a impressão digital, o rosto ou o PIN do dispositivo.
Uma chave de acesso precisa ser criada, associada a uma conta de usuário e ter a chave pública armazenada no servidor antes que o usuário possa fazer login com ela.
Como funciona
Um usuário pode ser solicitado a criar uma chave de acesso em uma das seguintes situações:
- Quando um usuário faz login usando uma senha.
- Quando um usuário faz login usando uma chave de acesso de outro dispositivo (ou seja, o
authenticatorAttachment
écross-platform
). - Em uma página dedicada em que os usuários podem gerenciar as chaves de acesso.
Para criar uma chave de acesso, use a API WebAuthn.
Os quatro componentes do fluxo de registro da chave de acesso são:
- Back-end: o servidor de back-end que contém o banco de dados de contas que armazena a chave pública e outros metadados sobre a chave de acesso.
- Front-end: o front-end que se comunica com o navegador e envia solicitações de busca para o back-end.
- Navegador: o navegador do usuário que está executando o JavaScript.
- Authenticator: o autenticador do usuário que cria e armazena a chave de acesso. Isso pode incluir o gerenciador de senhas no mesmo dispositivo que o navegador (por exemplo, ao usar o Windows Hello) ou em outro dispositivo, como um smartphone.
Para adicionar uma nova chave de acesso a uma conta de usuário, siga estas etapas:
- Um usuário faz login no site.
- Depois que o usuário faz login, ele solicita a criação de uma chave de acesso no front-end, por exemplo, pressionando um botão "Criar uma chave de acesso".
- O front-end solicita informações do back-end para criar uma chave de acesso, como informações do usuário, um desafio e os IDs de credencial a serem excluídos.
- O front-end chama
navigator.credentials.create()
para criar uma chave de acesso. Essa chamada retorna uma promessa. - Uma chave de acesso é criada depois que o usuário dá consentimento usando o bloqueio de tela do dispositivo. A promessa é resolvida, e uma credencial de chave pública é retornada para o front-end.
- O front-end envia a credencial de chave pública para o back-end e armazena o ID da credencial e a chave pública associada à conta do usuário para futuras autenticações.
Compatibilidades
A maioria dos navegadores oferece suporte ao WebAuthn, mas há pequenas lacunas. Consulte Suporte a dispositivos: chaves de acesso.dev para saber qual combinação de navegadores e sistemas operacionais oferece suporte à criação de chaves de acesso.
Criar uma chave de acesso
Confira como um front-end deve operar em uma solicitação para criar uma nova chave de acesso.
Detecção de recursos
Antes de mostrar o botão "Criar uma chave de acesso", verifique se:
- O navegador oferece suporte para WebAuthn com
PublicKeyCredential
.
- O dispositivo oferece suporte a um autenticador de plataforma (pode criar uma chave de acesso e
autenticar com ela) com
PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable()
.
- O navegador oferece suporte à IU condicional do
WebAuthn com
PublicKeyCredenital.isConditionalMediationAvailable()
.
// Availability of `window.PublicKeyCredential` means WebAuthn is usable.
// `isUserVerifyingPlatformAuthenticatorAvailable` means the feature detection is usable.
// `isConditionalMediationAvailable` means the feature detection is usable.
if (window.PublicKeyCredential &&
PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable &&
PublicKeyCredential.isConditionalMediationAvailable) {
// Check if user verifying platform authenticator is available.
Promise.all([
PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable(),
PublicKeyCredential.isConditionalMediationAvailable(),
]).then(results => {
if (results.every(r => r === true)) {
// Display "Create a new passkey" button
}
});
}
Até que todas as condições sejam atendidas, as chaves de acesso não serão compatíveis com esse navegador. O botão "Criar uma nova chave de acesso" não vai aparecer até esse momento.
Buscar informações importantes do back-end
Quando o usuário clica no botão, informações importantes são coletadas para chamar
navigator.credentials.create()
do back-end:
challenge
: um desafio gerado pelo servidor em ArrayBuffer para este registro. Isso é necessário, mas não usado durante o registro, a menos que a autenticação esteja ativada, um tema avançado que não é abordado aqui.user.id
: o ID exclusivo de um usuário. Esse valor precisa ser um ArrayBuffer que não inclua informações de identificação pessoal, por exemplo, endereços de e-mail ou nomes de usuário. Um valor aleatório de 16 bytes gerado por conta funciona bem.user.name
: esse campo precisa conter um identificador exclusivo da conta que o usuário vai reconhecer, como endereço de e-mail ou nome de usuário. Ele vai ser exibido no seletor de contas. Se você utiliza um nome de usuário, use o mesmo valor da autenticação por senha.user.displayName
: este campo é um nome obrigatório e mais fácil de usar para a conta. Ele não precisa ser exclusivo e pode ser o nome escolhido pelo usuário. Se o site não tiver um valor adequado para incluir aqui, transmita uma string vazia. Essa informação pode ser exibida no seletor de contas dependendo do navegador.excludeCredentials
: impede o registro do mesmo dispositivo fornecendo uma lista de IDs de credencial já registrados. O membrotransports
, se fornecido, precisa conter o resultado da chamada degetTransports()
durante o registro de cada credencial.
Chamar a API WebAuthn para criar uma chave de acesso
Chame navigator.credentials.create()
para criar uma nova chave de acesso. A API retorna
uma promessa, aguardando a interação do usuário exibindo uma caixa de diálogo modal.
const publicKeyCredentialCreationOptions = {
challenge: *****,
rp: {
name: "Example",
id: "example.com",
},
user: {
id: *****,
name: "john78",
displayName: "John",
},
pubKeyCredParams: [{alg: -7, type: "public-key"},{alg: -257, type: "public-key"}],
excludeCredentials: [{
id: *****,
type: 'public-key',
transports: ['internal'],
}],
authenticatorSelection: {
authenticatorAttachment: "platform",
requireResidentKey: true,
}
};
const credential = await navigator.credentials.create({
publicKey: publicKeyCredentialCreationOptions
});
// Encode and send the credential to the server for verification.
Os parâmetros não explicados acima são:
rp.id
: um ID de RP é um domínio, e um site pode especificar o próprio domínio ou um sufixo registrável. Por exemplo, se a origem de uma RP forhttps://login.example.com:1337
, o ID da RP poderá serlogin.example.com
ouexample.com
. Se o ID da RP for especificado comoexample.com
, o usuário poderá fazer a autenticação emlogin.example.com
ou em qualquer subdomínio emexample.com
.rp.name
: o nome do RP.pubKeyCredParams
: esse campo especifica os algoritmos de chave pública compatíveis com a RP. Recomendamos definir como[{alg: -7, type: "public-key"},{alg: -257, type: "public-key"}]
. Isso especifica a compatibilidade de ECDSA com P-256 e RSA PKCS#1, além de oferecer cobertura completa.authenticatorSelection.authenticatorAttachment
: defina como"platform"
se a criação da chave de acesso for um upgrade de uma senha, por exemplo, em uma promoção após o login."platform"
indica que o RP quer um autenticador de plataforma (um autenticador incorporado ao dispositivo da plataforma) que não solicite a inserção de, por exemplo, uma chave de segurança USB. O usuário tem uma opção mais simples para criar uma chave de acesso.authenticatorSelection.requireResidentKey
: define como um booleano "true". Uma credencial detectável (chave residente) armazena informações do usuário na chave de acesso e permite que os usuários selecionem a conta após a autenticação. Saiba mais sobre as credenciais detectáveis em Detalhamento de credenciais detectáveis.authenticatorSelection.userVerification
: indica se a verificação de um usuário usando o bloqueio de tela do dispositivo é"required"
,"preferred"
ou"discouraged"
. O padrão é"preferred"
, o que significa que o autenticador pode pular a verificação do usuário. Defina como"preferred"
ou omita a propriedade.
Enviar a credencial de chave pública retornada para o back-end
Depois que o usuário consente usando o bloqueio de tela do dispositivo, uma chave de acesso é criada e a promessa é resolvida, retornando um objeto PublicKeyCredential para o front-end.
A promessa pode ser rejeitada por diferentes motivos. É possível processar esses erros
verificando a propriedade name
do objeto Error
:
InvalidStateError
: uma chave de acesso já existe no dispositivo. Nenhuma caixa de diálogo de erro será mostrada ao usuário, e o site não deve tratar isso como um erro. O usuário queria que o dispositivo local fosse registrado, e ele foi.NotAllowedError
: o usuário cancelou a operação.- Outras exceções: algo inesperado aconteceu. O navegador mostra uma caixa de diálogo de erro para o usuário.
O objeto de credencial de chave pública contém as seguintes propriedades:
id
: um ID codificado em Base64URL da chave de acesso criada. Esse ID ajuda o navegador a determinar se uma chave de acesso correspondente está no dispositivo após a autenticação. Esse valor precisa ser armazenado no banco de dados no back-end.rawId
: uma versão ArrayBuffer do ID da credencial.response.clientDataJSON
: dados do cliente codificados em ArrayBuffer.response.attestationObject
: um objeto de atestado codificado por ArrayBuffer. Ele contém informações importantes, como um ID da RP, sinalizações e uma chave pública.authenticatorAttachment
: retorna"platform"
quando a credencial é criada em um dispositivo com suporte à chave de acesso.type
: esse campo é sempre definido como"public-key"
.
Se você usar uma biblioteca para processar o objeto de credencial de chave pública no back-end, recomendamos enviar o objeto inteiro para o back-end depois de codificá-lo parcialmente com base64url.
Salvar a credencial
Ao receber a credencial de chave pública no back-end, transmita-a à biblioteca FIDO para processar o objeto.
Em seguida, é possível armazenar as informações extraídas da credencial no banco de dados para uso futuro. A lista a seguir inclui algumas propriedades típicas para salvar:
- ID da credencial (chave primária)
- ID do usuário
- Chave pública
A credencial de chave pública também inclui as seguintes informações que você pode salvar no banco de dados:
- Flag de qualificação
para backup:
true
se o dispositivo estiver qualificado para a sincronização de chave de acesso. - Flag
de estado de backup:
true
se a chave de acesso criada está definida para ser sincronizada. - Transportes:
uma lista de transportes compatíveis com o dispositivo.
"internal"
significa que o dispositivo oferece suporte a uma chave de acesso."hybrid"
significa que ele também oferece suporte à autenticação em outro dispositivo.
Siga as instruções mais detalhadas em Registro de chave de acesso no servidor.
Para autenticar o usuário, leia Fazer login com uma chave de acesso usando o preenchimento automático de formulários.