Credentials Management API – Terra Webmail

Sr. Web Engineer na empresa Azion Technologies no time de Sudoers focado em aplicaçao RUM (Real User Monitoring/Measuring). Possui histório na empresa Terra Networks no time de Tecnologia em Porto Alegre. Lá passou por experiências nos times de: SVA, Tecnologia Portal, Entertenimento e Tecnologia de E-mail. Como último passo, teve a oportunidade fazer parte da criação do primeiro time Full DevOps.

Este artigo tem como objetivo mostrar por que e como foi implementada a Credential Management, bem como os benefícios dessa API, usando como exemplo o login do novo Terra Webmail.

LET’S GO BABY

Sabemos que hoje em dia, por mais que pareça superficialmente simples realizar a implementação de um login, logo mais a frente pode se tornar um Frankenstein ou até mesmo acabar em um grau de complexidade alto. Muitas vezes, além de gerenciar o login da nossa aplicação, temos os logins de terceiros [Facebook, Twitter, GitHub, Google].

Como temos por costume não compartilhar senhas entre aplicações por motivos de segurança, acabamos tendo um problema para a memorizar todas elas – é nessa hora que entra o trabalho da Credential Management API. Olhando por cima, temos uma lista de:

Esses são os mais comuns, uma pessoa pode ter muito mais que isso para memorizar…

BENEFÍCIOS

  • facilita a escolha em caso de múltiplos usuários;
  • permite uso de interface nativa para múltiplos devices;
  • identifica o login que o usuário fez anteriormente na página, mesmo que o usuário não tenha autologin no browser, permitindo a ele se logar com apenas um tap/click.
  • possilita iteração com o browser já que ele autopreenche campos de login/senha atualmente;
  • oferece auto sign in entre diferentes dispositivos;

AUTO SIGN IN

Esse comportamento nos fez dizer “wow!”

Caso você esteja logado em sua no Google Chrome e faça login em outro dispositivo na mesma página com a mesma conta, o browser identificará que foi efetuado o login e, com isso, ocorrerá o auto sign in.

CREDENTIALS MANAGEMENT API E SEUS PILARES

A API tem como base três pilares:

  • salvar/gerenciar os dados da credencial;
  • permitir acesso com apenas um tap no seletor de contas;
  • simplificar o fluxo de acesso;

PASSO 1 – EFETUANDO LOGIN E ARMAZENANDO A CREDENCIAL

Aqui, vamos ver como foi implementada essa feature no novo Terra Webmail.

Temos nossa tela de login com um formulário que contém dois campos:

  • usuário
  • senha

var loginForm = document.querySelector('#signin');
loginForm.addEventListener('submit', function(e) {
    e.preventDefault();

    validateLoginForm().then(function(res) {
        doLogin(res.user, res.pwd);
    });
});

O usuário irá digitar seu username/password para efetuar o login pela primeira vez e aí começará a mágica do Credentials.

Podemos ver que, quando o evento de envio do formulário for disparado, os valores do formulário de login serão validados. Caso esteja tudo OK, vai disparar a funcão doLogin, que será responsável por efetuar o login efetivo e salvar a credencial usando a Credentials Management API.

Um pouco antes de entrarmos no login, vamos validar se a feature está disponível no browser atual que estamos usando.


var cmapiAvailable = window.PasswordCredential && 'credentials' in navigator;

Agora que sabemos se está ou não disponível, podemos seguir nossa implementação.


function doLogin(user, pwd) {
    return authenticate(user, pwd).then(function(response) {
        // var cmapiAvailable = window.PasswordCredential && 'credentials' in navigator;
        if(cmapiAvailable) {
            var pwdCred = new window.PasswordCredential({
                id: user,
                password: pwd
            });
            navigator.credentials.store(pwdCred);
        }

        return response;
    });
};

Agora, iremos ver o que a função doLogin faz. Ela recebe dois parâmetros, que são os responsáveis por realizar a autenticação:

  • user – username
  • pwd – password

Após nos certificarmos de que temos a feature disponível para usá-la, iremos pegar os parâmetros user e pwd e criar um objeto JavaScript com os atributos id e password. Logo na próxima linha, passaremos esse objeto para uma nova instância de PasswordCredential.

A variável pwdCred armazenará um objeto de credencial, o qual será possível armazenar no browser.

Esse foi o primeiro passo: efetuamos o login e, logo em seguida, a credencial foi armazenada.

Pronto. Mais fácil do que se imaginava, certo?

PASSO 2 – VERIFICANDO CREDENCIAL SALVA E AUTO SIGN IN


function autoSignin() {
    // var cmapiAvailable = window.PasswordCredential && 'credentials' in navigator;
    if(!cmapiAvailable) {
        return;
    }

    navigator.credentials.get({
        password: true,
        mediation: 'optional'
    }).then(function(cred) {
        if(cred) {
            doLogin(cred.id, cred.password);
        }
    });
};

A função autoSignin é disparada logo após o carregamento da página por completo. Agora, iremos ver como e quando buscaremos a credencial caso ela seja existente.

Como já vimos, iremos na primeira linha verificar a existência da API. Caso ela exista, “matamos” o fluxo.

Agora, sim, usaremos o método get do navigator.credentials em que temos alguns parâmetros para cuidar na config do objeto. Para entender melhor, temos uma demonstração logo abaixo:

O atributo password caso não seja true, não conseguirá pegar a credencial caso existente.

O mediation pode ter os seguintes valores:

  • silent: com uma ou mais pessoas, caso tenha credencial salva, tentará logar de forma silenciosa. Caso preventSilentAccess() seja disparado antes, irá ignorar a ação de tentar logar de forma silenciosa e automática.
  • optional: com uma pessoa, caso tenha credencial salva, tentará logar de forma silenciosa. Caso preventSilentAccess() seja disparado antes, irá ignorar a ação de tentar logar de forma automática e abrirá o seletor de contas.
  • required: sempre exibirá o seletor de contas caso já tenha memorizado alguma credencial.

POR QUE ESTAMOS USANDO OPTIONAL?

Vamos entender linha por linha.

Estamos dizendo que caso já tenha sido efetuada e salva a credencial de um login, e o usuário não tenha disparado preventSilentAccess(), ele irá tentar logar de forma automática e silenciosa.

Não havendo a credencial porque o usuário disparou o preventSilentAccess(), ‘optional’ respeita a opção do usuário e abrirá o seletor de contas caso um ou mais usernames já estejam salvos.

PASSO 3 – LOGOUT


var logoutBtn = document.querySelector('a.logout');
logoutBtn.addEventListener('click', logout);

A nossa função que efetuará o logout irá ocorrer após um clique no botão de sair.


function logout() {
    if(cmapiAvailable) {
        navigator.credentials.preventSilentAccess();
    }

    fetch({
        url: '/ws/signout',
        withCredentials: true
    }).then(function() {
        window.location = '/signout' + window.location.search;
    });
};

Optamos por permitir que o usuário tenha o poder de cancelar o auto sign in. Para isso, é necessário disparar a função preventSilentAccess(), que é a responsável por comunicar a API que, na próxima visita, não deve disparar o auto sign in.

CONFIGURAÇÕES – chrome://password-manager-internals/

Anteriormente, citei que o mediation: ‘optional’ respeita a escolha do usuário. Essa escolha ocorre na opção Auto Sign-in.

DEBUGGER – chrome://password-manager-internals/

É possível acompanhar o que está acontecendo com a API, ver quando fluxos de auto sign in e sign out ocorrem, qual formulário ele está interceptando, entre outras coisas.

DESVANTAGENS

Por enquanto, apenas o Chrome tem suporte para essa feature, tanto desktop quanto mobile.
Porém, a API w3c credential management já está em draft na W3C.
Em um futuro breve teremos uma implementação cross browser.

REFERÊNCIAS


BrazilJS é uma iniciativa NASC