Simplificar o fluxo de login com a API de gerenciamento de credenciais

Para oferecer uma experiência sofisticada, é importante ajudar os usuários a se autenticarem no seu site. Os usuários autenticados podem interagir entre si usando um perfil dedicado, sincronizar dados entre dispositivos ou processar dados off-line. A lista é extensa. No entanto, criar, lembrar e digitar senhas tende a ser incômodo para os usuários finais, especialmente em telas de dispositivos móveis, o que os leva a reutilizar as mesmas senhas em sites diferentes. Isso, é claro, é um risco de segurança.

A versão mais recente do Chrome (51) oferece suporte à Credential Management API. É uma proposta de padrão do W3C que dá aos desenvolvedores acesso programático ao gerenciador de credenciais de um navegador e ajuda os usuários a fazer login com mais facilidade.

O que é a API Credential Management?

A API Credential Management permite que os desenvolvedores armazenem e recuperem credenciais de senha e federadas, além de oferecer três funções:

  • navigator.credentials.get()
  • navigator.credentials.store()
  • navigator.credentials.requireUserMediation()

Ao usar essas APIs simples, os desenvolvedores podem fazer coisas poderosas, como:

  • Permita que os usuários façam login com apenas um toque.
  • Lembre-se da conta federada que o usuário usou para fazer login.
  • Fazer login novamente quando uma sessão expirar.

Na implementação do Chrome, as credenciais são armazenadas no gerenciador de senhas do Chrome. Se os usuários fizerem login no Chrome, eles poderão sincronizar as senhas entre dispositivos. Essas senhas sincronizadas também podem ser compartilhadas com apps Android que integraram a API Smart Lock for Passwords para Android para uma experiência perfeita em várias plataformas.

Como integrar a API Credential Management ao seu site

A maneira como você usa a API Credential Management com seu site pode variar dependendo da arquitetura dele. É um app de página única? É uma arquitetura legada com transições de página? O formulário de login está localizado apenas na parte de cima da página? Os botões de login estão localizados em todos os lugares? Os usuários podem navegar pelo seu site sem fazer login? A federação funciona dentro de janelas pop-up? Ou ela exige interação em várias páginas?

É quase impossível cobrir todos esses casos, mas vamos analisar um app típico de página única.

  • A página de cima é um formulário de registro.
  • Ao tocar no botão "Fazer login", os usuários acessam um formulário de login.
  • Os formulários de registro e de login têm as opções típicas de credenciais de ID/senha e federação, por exemplo, com o Login do Google e do Facebook.

Ao usar a API Credential Management, você poderá adicionar os seguintes recursos ao site, por exemplo:

  • Mostrar um seletor de contas ao fazer login:mostra uma interface nativa do seletor de contas quando um usuário toca em "Fazer login".
  • Armazenar credenciais:após o sucesso do login, ofereça a opção de armazenar as informações de credenciais no gerenciador de senhas do navegador para uso posterior.
  • Permitir que o usuário faça login automaticamente:permita que o usuário faça login novamente se uma sessão tiver expirado.
  • Mediação de login automático:depois que um usuário faz logout, desative o login automático para a próxima visita dele.

Teste esses recursos implementados em um site de demonstração com um exemplo de código.

Mostrar o seletor de contas ao fazer login

Entre o toque do usuário em um botão "Fazer login" e a navegação para um formulário de login, é possível usar navigator.credentials.get() para receber informações de credenciais. O Chrome mostra uma IU do seletor de conta, na qual o usuário pode escolher uma conta.

Uma interface de usuário do seletor de conta é exibida para que o usuário selecione uma conta para fazer login.
Uma interface de seleção de contas aparece para que o usuário selecione uma conta para fazer login

Como acessar um objeto de credencial de senha

Para mostrar as credenciais de senha como opções de conta, use password: true.

navigator.credentials.get({
    password: true, // `true` to obtain password credentials
}).then(function(cred) {
    // continuation
    ...

Como usar uma credencial de senha para fazer login

Depois que o usuário seleciona a conta, a função de resolução recebe uma credencial de senha. É possível enviá-lo ao servidor usando fetch():

    // continued from previous example
}).then(function(cred) {
    if (cred) {
    if (cred.type == 'password') {
        // Construct FormData object
        var form = new FormData();

        // Append CSRF Token
        var csrf_token = document.querySelector('csrf_token').value;
        form.append('csrf_token', csrf_token);

        // You can append additional credential data to `.additionalData`
        cred.additionalData = form;

        // `POST` the credential object as `credentials`.
        // id, password and the additional data will be encoded and
        // sent to the url as the HTTP body.
        fetch(url, {           // Make sure the URL is HTTPS
        method: 'POST',      // Use POST
        credentials: cred    // Add the password credential object
        }).then(function() {
        // continuation
        });
    } else if (cred.type == 'federated') {
        // continuation

Como usar uma credencial federada para fazer login

Para mostrar contas federadas a um usuário, adicione federated, que usa uma matriz de provedores de identidade, às opções de get().

Quando várias contas são armazenadas no gerenciador de senhas.
Quando várias contas são armazenadas no gerenciador de senhas
navigator.credentials.get({
    password: true, // `true` to obtain password credentials
    federated: {
    providers: [  // Specify an array of IdP strings
        'https://accounts.google.com',
        'https://www.facebook.com'
    ]
    }
}).then(function(cred) {
    // continuation
    ...

É possível examinar a propriedade type do objeto de credencial para saber se ela é PasswordCredential (type == 'password') ou FederatedCredential (type == 'federated'). Se a credencial for uma FederatedCredential, é possível chamar a API apropriada usando as informações que ela contém.

    });
} else if (cred.type == 'federated') {
    // `provider` contains the identity provider string
    switch (cred.provider) {
    case 'https://accounts.google.com':
        // Federated login using Google Sign-In
        var auth2 = gapi.auth2.getAuthInstance();

        // In Google Sign-In library, you can specify an account.
        // Attempt to sign in with by using `login_hint`.
        return auth2.signIn({
        login_hint: cred.id || ''
        }).then(function(profile) {
        // continuation
        });
        break;

    case 'https://www.facebook.com':
        // Federated login using Facebook Login
        // continuation
        break;

    default:
        // show form
        break;
    }
}
// if the credential is `undefined`
} else {
// show form
Fluxograma de gerenciamento de credenciais.

Armazenar credenciais

Quando um usuário faz login no seu site usando um formulário, você pode usar navigator.credentials.store() para armazenar a credencial. O usuário vai ser solicitado a armazená-lo ou não. Dependendo do tipo de credencial, use new PasswordCredential() ou new FederatedCredential() para criar um objeto de credencial que você quer armazenar.

O Chrome pergunta aos usuários se eles querem armazenar a credencial (ou um provedor de federação).
O Chrome pergunta aos usuários se eles querem armazenar a credencial (ou um provedor de federação)

Criar e armazenar uma credencial de senha de um elemento de formulário

O código a seguir usa atributos autocomplete para mapear os elementos do formulário automaticamente para parâmetros de objeto PasswordCredential.

HTML html <form id="form" method="post"> <input type="text" name="id" autocomplete="username" /> <input type="password" name="password" autocomplete="current-password" /> <input type="hidden" name="csrf_token" value="******" /> </form>

JavaScript

var form = document.querySelector('\#form');
var cred = new PasswordCredential(form);
// Store it
navigator.credentials.store(cred)
.then(function() {
    // continuation
});

Como criar e armazenar uma credencial federada

// After a federation, create a FederatedCredential object using
// information you have obtained
var cred = new FederatedCredential({
    id: id,                                  // The id for the user
    name: name,                              // Optional user name
    provider: 'https://accounts.google.com',  // A string that represents the identity provider
    iconURL: iconUrl                         // Optional user avatar image url
});
// Store it
navigator.credentials.store(cred)
.then(function() {
    // continuation
});
Diagrama do fluxo de login.

Permitir que o usuário faça login automaticamente

Quando um usuário sai do seu site e volta mais tarde, é possível que a sessão tenha expirado. Não force o usuário a digitar a senha toda vez que ele voltar. Permita que o usuário faça login automaticamente.

Quando um usuário é conectado automaticamente, uma notificação aparece.
Quando um usuário faz login automaticamente, uma notificação aparece.

Como receber um objeto de credencial

navigator.credentials.get({
    password: true, // Obtain password credentials or not
    federated: {    // Obtain federation credentials or not
    providers: [  // Specify an array of IdP strings
        'https://accounts.google.com',
        'https://www.facebook.com'
    ]
    },
    unmediated: true // `unmediated: true` lets the user automatically sign in
}).then(function(cred) {
    if (cred) {
    // auto sign-in possible
    ...
    } else {
    // auto sign-in not possible
    ...
    }
});

O código vai ser semelhante ao que você viu na seção "Mostrar o seletor de contas ao fazer login". A única diferença é que você vai definir unmediated: true.

Isso resolve a função imediatamente e fornece a credencial para fazer login no usuário automaticamente. Há algumas condições:

  • O usuário reconheceu o recurso de login automático em uma recepção calorosa.
  • O usuário já fez login no site usando a API Credential Management.
  • O usuário tem apenas uma credencial armazenada para sua origem.
  • O usuário não saiu explicitamente na sessão anterior.

Se alguma dessas condições não for atendida, a função será rejeitada.

Diagrama de fluxo de objetos de credenciais

Mediar o login automático

Quando um usuário faz logout do seu site, é sua responsabilidade garantir que o usuário não faça login automaticamente. Para garantir isso, a API Credential Management oferece um mecanismo chamado mediação. É possível ativar o modo de mediação chamando navigator.credentials.requireUserMediation(). Enquanto o status de mediação do usuário para a origem estiver ativado, usando unmediated: true com navigator.credentials.get(), essa função será resolvida com undefined.

Como mediar o login automático

navigator.credentials.requireUserMediation();
Fluxograma de login automático.

Perguntas frequentes

É possível que o JavaScript no site recupere uma senha não criptografada? Não. Só é possível receber senhas como parte de PasswordCredential, e elas não podem ser expostas de nenhuma forma.

É possível armazenar três conjuntos de dígitos para um ID usando a API Credential Management? No momento, não. Seu feedback sobre a especificação será muito bem-vindo.

Posso usar a API Credential Management dentro de um iframe? A API é restrita a contextos de nível superior. As chamadas para .get() ou .store() em um iframe são resolvidas imediatamente sem efeito.

Posso integrar minha extensão do Chrome de gerenciamento de senhas à API Credential Management? É possível substituir navigator.credentials e conectá-lo à extensão do Chrome para get() ou credenciais store().

Recursos

Para saber mais sobre a API Credential Management, consulte o guia de integração.