Criar uma chave de acesso para logins sem senha

As chaves de acesso tornam as contas de usuário mais seguras, simples e fáceis de usar.

Publicado em: 12 de outubro de 2022. Última atualização: 9 de abril de 2026

O uso de chaves de acesso aumenta a segurança, simplifica os logins e substitui as senhas. Ao contrário das senhas comuns, que os usuários precisam lembrar e inserir manualmente, as chaves de acesso usam mecanismos de bloqueio de tela do dispositivo, como biometria ou PINs, e reduzem os riscos de phishing e roubo de credenciais.

As chaves de acesso são sincronizadas entre dispositivos usando provedores como o Gerenciador de senhas do Google e o conjunto de chaves do iCloud.

Uma chave de acesso precisa ser criada, armazenando a chave privada com segurança no provedor junto com os metadados necessários e a chave pública armazenada no servidor para autenticação. A chave privada emite uma assinatura após a verificação do usuário no domínio válido, tornando as chaves de acesso resistentes a phishing. A chave pública verifica a assinatura sem armazenar credenciais sensíveis, o que torna as chaves de acesso resistentes ao roubo de credenciais.

Como funciona a criação de uma chave de acesso

Antes que um usuário possa fazer login com uma chave de acesso, você precisa criar a chave de acesso, associá-la a uma conta de usuário e armazenar a chave pública no servidor.

Você pode pedir que os usuários criem uma chave de acesso em uma das seguintes situações:

  • Durante ou após a inscrição.
  • Depois de fazer login.
  • Depois de fazer 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: armazena detalhes da conta do usuário, incluindo a chave pública.
  • Front-end: se comunica com o navegador e busca os dados necessários do back-end.
  • Navegador: executa seu JavaScript e interage com a API WebAuthn.
  • Provedor de chave de acesso: cria e armazena a chave de acesso. Normalmente, é um gerenciador de senhas, como o Gerenciador de senhas do Google, ou uma chave de segurança.
O processo de criação e registro de uma chave de acesso
O processo de criação e registro de uma chave de acesso.

Antes de criar uma chave de acesso, verifique se o sistema atende a estes pré-requisitos:

  • A conta de usuário é verificada por um método seguro (por exemplo, e-mail, verificação por telefone ou federação de identidade) em um período significativamente curto.

  • O front-end e o back-end podem se comunicar com segurança para trocar dados de credenciais.

  • O navegador é compatível com a WebAuthn e a criação de chaves de acesso.

Vamos mostrar como verificar a maioria delas nas seções a seguir.

Quando o sistema atende a essas condições, o processo a seguir acontece para criar uma chave de acesso:

  1. O sistema aciona o processo de criação de chave de acesso quando o usuário inicia a ação. Por exemplo, clicando em um botão "Criar uma chave de acesso" na página de gerenciamento de chaves de acesso ou depois de concluir o registro.
  2. O front-end solicita os dados de credenciais necessários do back-end, incluindo informações do usuário, um desafio e IDs de credenciais para evitar duplicatas.
  3. O front-end chama navigator.credentials.create() para pedir ao provedor de chaves de acesso do dispositivo que gere uma chave de acesso usando as informações do back-end. Essa chamada retorna uma promessa.
  4. O dispositivo do usuário autentica o usuário usando um método biométrico, PIN ou padrão para criar a chave de acesso.
  5. O provedor de chave de acesso cria uma chave de acesso e retorna uma credencial de chave pública para o front-end, resolvendo a promessa.
  6. O front-end envia a credencial de chave pública gerada para o back-end.
  7. O back-end armazena a chave pública e outros dados importantes para autenticação futura.
  8. O back-end notifica o usuário (por exemplo, por e-mail) para confirmar a criação da chave de acesso e detectar possíveis acessos não autorizados.

Esse processo garante um registro de chaves de acesso seguro e integrado para os usuários.

Compatibilidades

A maioria dos navegadores oferece suporte ao WebAuthn, com algumas pequenas lacunas. Consulte passkeys.dev para detalhes sobre a compatibilidade com navegadores e sistemas operacionais.

Criar uma chave de acesso

Para criar uma nova chave de acesso, o front-end precisa seguir este processo:

  1. Verifique a compatibilidade.
  2. Buscar informações do back-end.
  3. Chame a API WebAuth para criar uma chave de acesso.
  4. Envie a chave pública retornada para o back-end.
  5. Salve a credencial.

As seções a seguir mostram como fazer isso.

Verificar a compatibilidade

Antes de mostrar um botão "Criar uma nova chave de acesso", o front-end precisa verificar se:

  • O navegador é compatível com o WebAuthn com PublicKeyCredential.

Browser Support

  • Chrome: 67.
  • Edge: 18.
  • Firefox: 60.
  • Safari: 13.

Source

Browser Support

  • Chrome: 133.
  • Edge: 133.
  • Firefox: 135.
  • Safari: 17.4.

Source

  • O navegador é compatível com a interface condicional do WebAuthn com conditionalGet.

  • O dispositivo é compatível com um autenticador de plataforma (pode criar uma chave de acesso e fazer autenticação no dispositivo) com passkeyPlatformAuthenticator.

O snippet de código a seguir mostra como verificar a compatibilidade antes de exibir as opções relacionadas à chave de acesso.

if (window.PublicKeyCredential && PublicKeyCredential.getClientCapabilities) {
  const capabilities = await PublicKeyCredential.getClientCapabilities();
  if (capabilities.conditionalGet === true &&
      capabilities.passkeyPlatformAuthenticator === true) {
    // The browser supports passkeys and the conditional UI.
  }
}

Neste exemplo, o botão Criar uma nova chave de acesso só será mostrado se todas as condições forem atendidas.

Buscar informações do back-end

Quando o usuário clicar no botão, busque as informações necessárias no back-end para chamar navigator.credentials.create().

O snippet de código a seguir mostra um objeto JSON com as informações necessárias para chamar navigator.credentials.create():

// Example `PublicKeyCredentialCreationOptions` contents
{
  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,
  }
}

Os pares de chave-valor no objeto contêm as seguintes informações:

  • challenge: um desafio gerado pelo servidor em ArrayBuffer para este registro.
  • rp.id: um ID de RP (ID da parte confiante), um domínio e um site podem especificar o domínio ou um sufixo registrável. Por exemplo, se a origem de uma RP for https://login.example.com:1337, o ID da RP poderá ser login.example.com ou example.com. Se o ID da RP for especificado como example.com, o usuário poderá fazer a autenticação em login.example.com ou em qualquer subdomínio em example.com. Consulte Permitir a reutilização de chaves de acesso em todos os seus sites com solicitações de origem relacionadas para mais informações.
  • rp.name: o nome da parte confiável (RP, na sigla em inglês). Ele foi descontinuado no WebAuthn L3, mas incluído por motivos de compatibilidade.
  • user.id: um ID de usuário exclusivo em ArrayBuffer, gerado na criação da conta. Ele precisa ser permanente, ao contrário de um nome de usuário que pode ser editado. O ID de usuário identifica uma conta, mas não pode conter informações de identificação pessoal (PII). Você provavelmente já tem um ID de usuário no seu sistema, mas, se necessário, crie um especificamente para chaves de acesso e mantenha-o livre de informações de identificação pessoal.
  • user.name: um identificador exclusivo da conta que o usuário vai reconhecer, como o endereço de e-mail ou o nome de usuário. e vai ser exibido no seletor de contas.
  • user.displayName: 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.
  • pubKeyCredParams: especifica os algoritmos de chave pública compatíveis com a RP (parte confiável). Recomendamos defini-lo como [{alg: -7, type: "public-key"},{alg: -257, type: "public-key"}]. Isso especifica a compatibilidade de ECDSA com P-256 e RSA PKCS#1 e oferece cobertura completa.
  • excludeCredentials: uma lista de IDs de credenciais já registradas. Evita o registro do mesmo dispositivo duas vezes ao fornecer uma lista de IDs de credencial já registrados. O membro transports precisa conter o resultado da chamada de getTransports() durante o registro de cada credencial, se fornecido.
  • authenticatorSelection.authenticatorAttachment: defina como "platform" junto com hint: ['client-device'] se esta criação de chave de acesso for um upgrade de uma senha, por exemplo, em uma promoção após um login. "platform" indica que o RP quer um autenticador de plataforma (incorporado ao dispositivo da plataforma) que não solicite, por exemplo, a inserção de uma chave de segurança USB. O usuário tem uma opção mais simples para criar uma chave de acesso.
  • authenticatorSelection.requireResidentKey: defina 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.
  • 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.

Recomendamos construir o objeto no servidor, codificar o ArrayBuffer com Base64URL e buscá-lo no front-end. Assim, é possível decodificar o payload usando PublicKeyCredential.parseCreationOptionsFromJSON() e transmiti-lo diretamente para navigator.credentials.create().

O snippet de código a seguir mostra como buscar e decodificar as informações necessárias para criar a chave de acesso.

// Fetch an encoded `PubicKeyCredentialCreationOptions` from the server.
const _options = await fetch('/webauthn/registerRequest');

// Deserialize and decode the `PublicKeyCredentialCreationOptions`.
const decoded_options = JSON.parse(_options);
const options = PublicKeyCredential.parseCreationOptionsFromJSON(decoded_options);
...

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 e mostrando uma caixa de diálogo modal.

Browser Support

  • Chrome: 60.
  • Edge: 18.
  • Firefox: 60.
  • Safari: 13.

Source

// Invoke WebAuthn to create a passkey.
const credential = await navigator.credentials.create({
  publicKey: options
});

Envie a credencial de chave pública retornada para o back-end

Depois que o usuário for verificado usando o bloqueio de tela do dispositivo, uma chave de acesso será criada e a promessa será resolvida retornando um objeto PublicKeyCredential para o front-end.

A promessa pode ser rejeitada por diferentes motivos. Para processar esses erros, verifique 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. 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.
  • AbortError: a operação foi cancelada.
  • Outras exceções: ocorreu um erro inesperado. 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: Um ArrayBuffer com dados do cliente codificados.
  • response.attestationObject: um objeto de atestado codificado em ArrayBuffer. Ele tem informações importantes, como um ID da RP, flags e uma chave pública.
  • authenticatorAttachment: retorna "platform" quando esta credencial é criada em um dispositivo compatível com chave de acesso.
  • type: este campo está sempre definido como "public-key".

Codifique o objeto com o método .toJSON(), serializa com JSON.stringify() e envie para o servidor.

...

// Encode and serialize the `PublicKeyCredential`.
const _result = credential.toJSON();
const result = JSON.stringify(_result);

// Encode and send the credential to the server for verification.  
const response = await fetch('/webauthn/registerResponse', {
  method: 'post',
  credentials: 'same-origin',
  body: result
});
...

Salvar a credencial

Depois de receber a credencial de chave pública no back-end, recomendamos usar uma biblioteca ou solução do lado do servidor em vez de escrever seu próprio código para processar uma credencial de chave pública.

Em seguida, armazene as informações recuperadas da credencial no banco de dados para uso futuro.

A lista a seguir inclui propriedades recomendadas para salvar:

  • ID da credencial: O ID da credencial retornado com a credencial de chave pública.
  • Nome da credencial: o nome da credencial. Nomeie-o de acordo com o provedor da chave de acesso que o criou, que pode ser identificado com base no AAGUID.
  • ID do usuário: o ID do usuário usado para criar a chave de acesso.
  • Chave pública: a chave pública retornada com a credencial de chave pública. Isso é necessário para verificar uma declaração de chave de acesso.
  • Data e hora de criação: registre a data e a hora da criação da chave de acesso. Isso é útil para identificar a chave de acesso.
  • Data e hora do último uso: registra a data e a hora em que o usuário usou a chave de acesso para fazer login pela última vez. Isso é útil para determinar qual chave de acesso o usuário usou (ou não usou).
  • AAGUID: Um identificador exclusivo do provedor de chaves de acesso.
  • Flag de qualificação para backup: true se o dispositivo estiver qualificado para a sincronização de chaves de acesso. Essas informações ajudam os usuários a identificar chaves de acesso sincronizáveis e vinculadas ao dispositivo (não sincronizáveis) na página de gerenciamento de chaves de acesso.

Siga instruções mais detalhadas em Registro de chave de acesso do lado do servidor

Sinalizar se o registro falhar

Se o registro de uma chave de acesso falhar, isso pode confundir o usuário. Se houver uma chave de acesso no provedor e disponível para o usuário, mas a chave pública associada não estiver armazenada no lado do servidor, as tentativas de login usando a chave de acesso nunca vão funcionar, e é difícil resolver o problema. Informe ao usuário se esse for o caso.

Para evitar essa condição, você pode informar uma chave de acesso desconhecida ao provedor usando a API Signal. Ao chamar PublicKeyCredential.signalUnknownCredential() com um ID de RP e um ID de credencial, o RP pode informar ao provedor de chaves de acesso que a credencial especificada foi removida ou não existe. O provedor da chave de acesso decide como lidar com esse indicador, mas, se houver suporte, a chave de acesso associada será removida.

// Detect authentication failure due to lack of the credential
if (response.status === 404) {
  // Feature detection
  if (PublicKeyCredential.signalUnknownCredential) {
    await PublicKeyCredential.signalUnknownCredential({
      rpId: "example.com",
      credentialId: "vI0qOggiE3OT01ZRWBYz5l4MEgU0c7PmAA" // base64url encoded credential ID
    });
  } else {
    // Encourage the user to delete the passkey from the password manager nevertheless.
    ...
  }
}

Para saber mais sobre a API Signal, leia Manter as chaves de acesso consistentes com as credenciais no seu servidor com a API Signal.

Enviar uma notificação para o usuário

Enviar uma notificação (como um e-mail) quando uma chave de acesso é registrada ajuda os usuários a detectar acessos não autorizados à conta. Se um invasor criar uma chave de acesso sem o conhecimento do usuário, ela vai continuar disponível para abusos futuros, mesmo depois que a senha for alterada. A notificação alerta o usuário e ajuda a evitar isso.

Lista de verificação

  • Verifique o usuário (de preferência usando e-mail ou um método seguro) antes de permitir que ele crie uma chave de acesso.
  • Evite criar chaves de acesso duplicadas para o mesmo provedor usando excludeCredentials.
  • Salve o AAGUID para identificar o provedor de chaves de acesso e nomear a credencial para o usuário.
  • Sinaliza se uma tentativa de registrar uma chave de acesso falha com PublicKeyCredential.signalUnknownCredential().
  • Envie uma notificação ao usuário depois de criar e registrar uma chave de acesso para a conta dele.

Recursos

Próxima etapa: Fazer login com uma chave de acesso usando o preenchimento automático de formulários.