Fazer login com uma chave de acesso usando o preenchimento automático de formulários

Crie uma experiência de login que aproveite as chaves de acesso e ainda acomode os usuários de senhas atuais.

As chaves de acesso substituem senhas e tornam as contas de usuário na Web mais seguras, simples e fáceis de usar. No entanto, a transição da autenticação baseada em senha para a baseada em chaves de acesso pode complicar a experiência do usuário. O uso do preenchimento automático de formulários para sugerir chaves de acesso pode ajudar a criar uma experiência unificada.

Por que usar o preenchimento automático de formulários para fazer login com uma chave de acesso?

Com uma chave de acesso, o usuário pode fazer login em um site usando a impressão digital, o rosto ou o PIN do dispositivo.

O ideal é que não haja usuários com senha, e o fluxo de autenticação poderia ser tão simples quanto um único botão de login. Quando o usuário toca no botão, uma caixa de diálogo de seletor de conta é exibida e ele pode escolher uma conta, desbloquear a tela para verificar e fazer login.

No entanto, a transição da senha para a autenticação baseada em chaves de acesso pode ser desafiadora. À medida que os usuários mudam para as chaves de acesso, as pessoas que usam senhas e sites ainda precisam acomodar os dois tipos de usuário. Os usuários não precisam se lembrar em quais sites mudaram para chaves de acesso. Portanto, pedir aos usuários para selecionar qual método usar antecipadamente seria uma UX ruim.

As chaves de acesso também são uma nova tecnologia. Explicá-los e garantir que os usuários se sintam confortáveis para usá-los pode ser um desafio para os sites. Podemos confiar em experiências conhecidas do usuário para o preenchimento automático de senhas e resolver os dois problemas.

interface condicional

Para criar uma experiência do usuário eficiente para usuários de chave de acesso e senha, você pode incluir chaves de acesso nas sugestões de preenchimento automático. Isso é chamado de interface condicional e faz parte do padrão WebAuthn.

Assim que o usuário toca no campo de entrada de nome de usuário, uma caixa de diálogo de sugestão de preenchimento automático é exibida, destacando as chaves de acesso armazenadas com sugestões de preenchimento automático de senha. Em seguida, o usuário pode escolher uma conta e usar o bloqueio de tela do dispositivo para fazer login.

Dessa forma, os usuários podem fazer login no seu site com o formulário atual como se nada tivesse mudado, mas com o benefício de segurança extra das chaves de acesso, se tiverem uma.

Como funciona

Para autenticar com uma chave de acesso, use a API WebAuthn.

Os quatro componentes em um fluxo de autenticação de chave de acesso são: o usuário:

  • 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: seu 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. Ele pode estar no mesmo dispositivo do navegador (por exemplo, ao usar o Windows Hello) ou em outro dispositivo, como um smartphone.
Diagrama de autenticação de chave de acesso
  1. Assim que um usuário acessa o front-end, ele solicita um desafio do back-end para autenticar com uma chave de acesso e chama navigator.credentials.get() para iniciar a autenticação com uma chave de acesso. Isso retorna um Promise.
  2. Quando o usuário coloca o cursor no campo de login, o navegador mostra uma caixa de diálogo de preenchimento automático de senha, incluindo chaves de acesso. Uma caixa de diálogo de autenticação vai aparecer se o usuário selecionar uma chave de acesso.
  3. Depois que o usuário verifica a identidade usando o bloqueio de tela do dispositivo, a promessa é resolvida e uma credencial de chave pública é retornada ao front-end.
  4. O front-end envia a credencial de chave pública para o back-end. O back-end verifica a assinatura em relação à chave pública da conta correspondente no banco de dados. Se ela for bem-sucedida, o usuário estará conectado.

Pré-requisitos

A interface WebAuthn condicional é compatível publicamente com o Safari no iOS 16, iPadOS 16 e macOS Ventura. Ele também está disponível no Chrome para Android, macOS e Windows 11 22H2.

Autenticar com uma chave de acesso pelo preenchimento automático de formulários

Quando um usuário quiser fazer login, você pode fazer uma chamada get condicional da WebAuthn para indicar que chaves de acesso podem ser incluídas nas sugestões de preenchimento automático. Uma chamada condicional para a API navigator.credentials.get() do WebAuthn não mostra a interface e permanece pendente até que o usuário escolha uma conta para fazer login nas sugestões de preenchimento automático. Se o usuário escolher uma chave de acesso, o navegador vai resolver a promessa com uma credencial em vez de preencher o formulário de login. A partir de então, é responsabilidade da página fazer o login do usuário.

Campo de entrada de anotação do formulário

Adicione um atributo autocomplete ao campo input do nome de usuário, se necessário. Anexe username e webauthn como tokens para permitir que ele sugira chaves de acesso.

<input type="text" name="username" autocomplete="username webauthn" ...>

Detecção de recursos

Antes de invocar uma chamada condicional de API WebAuthn, verifique se:

  • O navegador oferece suporte ao WebAuthn.
  • O navegador oferece suporte à interface condicional do WebAuthn.
// Availability of `window.PublicKeyCredential` means WebAuthn is usable.  
if (window.PublicKeyCredential &&  
    PublicKeyCredential.​​isConditionalMediationAvailable) {  
  // Check if conditional mediation is available.  
  const isCMA = await PublicKeyCredential.​​isConditionalMediationAvailable();  
  if (isCMA) {  
    // Call WebAuthn authentication  
  }  
}  

Buscar um desafio no servidor da RP

Busque um desafio do servidor da RP que seja necessário para chamar navigator.credentials.get():

  • challenge: um desafio gerado pelo servidor em um ArrayBuffer. Isso é necessário para evitar ataques de repetição. Gere um novo desafio a cada tentativa de login e desconsidere-o após um determinado período ou quando uma tentativa de login não for validada. Considere-o como um token CSRF.
  • allowCredentials: uma matriz de credenciais aceitáveis para essa autenticação. Transmita uma matriz vazia para permitir que o usuário selecione uma chave de acesso disponível em uma lista mostrada pelo navegador.
  • userVerification: indica se a verificação do 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.

Chame a API WebAuthn com a flag conditional para autenticar o usuário.

Chame navigator.credentials.get() para começar a aguardar a autenticação do usuário.

// To abort a WebAuthn call, instantiate an `AbortController`.
const abortController = new AbortController();

const publicKeyCredentialRequestOptions = {
  // Server generated challenge
  challenge: ****,
  // The same RP ID as used during registration
  rpId: 'example.com',
};

const credential = await navigator.credentials.get({
  publicKey: publicKeyCredentialRequestOptions,
  signal: abortController.signal,
  // Specify 'conditional' to activate conditional UI
  mediation: 'conditional'
});
  • rpId: um ID da RP é um domínio, e um site pode especificar o próprio domínio ou um sufixo que pode ser registrado. Esse valor precisa corresponder ao rp.id usado quando a chave de acesso foi criada.

Lembre-se de especificar mediation: 'conditional' para tornar a solicitação condicional.

Envie a credencial de chave pública retornada ao servidor da RP

Depois que o usuário seleciona uma conta e autoriza o uso do bloqueio de tela do dispositivo, a promessa é resolvida retornando um objeto PublicKeyCredential ao front-end da RP.

Uma promessa pode ser rejeitada por vários motivos. Gerencie os erros adequadamente, dependendo da propriedade name do objeto Error:

  • NotAllowedError: o usuário cancelou a operação.
  • Outras exceções: ocorreu algo inesperado. O navegador mostra uma caixa de diálogo de erro ao usuário.

O objeto de credencial de chave pública contém as seguintes propriedades:

  • id: o ID codificado em base64url da credencial da chave de acesso autenticada.
  • rawId: uma versão ArrayBuffer do ID da credencial.
  • response.clientDataJSON: um ArrayBuffer de dados do cliente. Esse campo contém informações como o desafio e a origem que o servidor da RP precisará verificar.
  • response.authenticatorData: um ArrayBuffer de dados do autenticador. Esse campo contém informações como o ID da RP.
  • response.signature: um ArrayBuffer da assinatura. Esse valor é o núcleo da credencial e precisa ser verificado no servidor.
  • response.userHandle: um ArrayBuffer que continha o ID do usuário definido no momento da criação. Esse valor poderá ser usado, em vez do ID da credencial, se o servidor precisar escolher os valores de ID usados ou se o back-end quiser evitar a criação de um índice nos IDs das credenciais.
  • authenticatorAttachment: retorna platform quando a credencial veio do dispositivo local. Caso contrário, cross-platform, especialmente quando o usuário tiver usado um smartphone para fazer login. Se o usuário precisar usar um smartphone para fazer login, peça que ele crie uma chave de acesso no dispositivo local.
  • type: este campo é sempre definido como "public-key".

Se você usar uma biblioteca para processar o objeto de credencial de chave pública no servidor RP, recomendamos enviar o objeto inteiro para o servidor depois de codificá-lo parcialmente com base64url.

Verificar a assinatura

Ao receber a credencial de chave pública no servidor, transmita-a para a biblioteca FIDO processar o objeto.

Procure o ID da credencial correspondente com a propriedade id. Se você precisar determinar a conta de usuário, use a propriedade userHandle, que é o user.id especificado ao criar a credencial. Confira se o signature da credencial pode ser verificado com a chave pública armazenada. Para fazer isso, recomendamos usar uma biblioteca do lado do servidor ou uma solução em vez de escrever seu próprio código. As bibliotecas de código aberto podem ser encontradas no repositório do GitHub awesome-webauth.

Depois que a credencial for verificada com uma chave pública correspondente, faça o login do usuário.

Recursos