Atualizações mais recentes na API de gerenciamento de credenciais

Algumas das atualizações descritas aqui são explicadas na sessão do Google I/O, Login seguro e fácil: como manter os usuários engajados:

Chrome 57

O Chrome 57 introduziu essa importante mudança ao API Credential Management.

As credenciais podem ser compartilhadas de um subdomínio diferente

Agora o Chrome pode recuperar uma credencial armazenada em um subdomínio diferente usando o API Credential Management. Por exemplo, se uma senha for armazenada em login.example.com, um script em www.example.com pode mostrá-lo como um dos itens de conta na caixa de diálogo do seletor de conta.

É preciso armazenar explicitamente a senha usando navigator.credentials.store(). assim, quando um usuário escolher uma credencial tocando na caixa de diálogo, a senha será transmitida e copiada para a origem atual.

Depois de armazenada, a senha fica disponível como uma credencial exatamente na mesma origem www.example.com em diante.

Na captura de tela a seguir, as informações de credenciais armazenadas em login.aliexpress.com está visível para m.aliexpress.com e disponível para o usuário escolher:

Seletor de conta mostrando os detalhes de login do subdomínio selecionado

Chrome 60

O Chrome 60 introduz várias mudanças importantes na API Credential Management:

A detecção de recursos requer atenção

Para verificar se a API Credential Management para acessar dados se as credenciais federadas estiverem disponíveis, verifique se window.PasswordCredential ou window.FederatedCredential está disponível.

if (window.PasswordCredential || window.FederatedCredential) {
  // The Credential Management API is available
}

O objeto PasswordCredential agora inclui uma senha

A API Credential Management adotou uma abordagem conservadora para o gerenciamento de senhas. Ele ocultava senhas do JavaScript, exigindo que os desenvolvedores enviar o objeto PasswordCredential diretamente ao servidor para validação por meio de uma extensão para a API fetch().

Mas essa abordagem introduziu uma série de restrições. Recebemos feedback informando que os desenvolvedores não conseguiram usar a API pelos seguintes motivos:

  • Ele precisou enviar a senha como parte de um objeto JSON.

  • Ele teve que enviar o valor de hash da senha para o servidor.

Depois de realizar uma análise de segurança e reconhecer que a ocultação de senhas do JavaScript não impediu todos os vetores de ataque com a eficácia que esperávamos. decidimos fazer uma mudança.

A API Credential Management agora inclui uma senha bruta em um objeto de credencial retornado para que você tenha acesso a ele como texto simples. Você pode usar métodos existentes para enviar informações de credenciais para seu servidor:

navigator.credentials.get({
    password: true,
    federated: {
    providers: [ 'https://accounts.google.com' ]
    },
    mediation: 'silent'
}).then(passwordCred => {
    if (passwordCred) {
    let form = new FormData();
    form.append('email', passwordCred.id);
    form.append('password', passwordCred.password);
    form.append('csrf_token', csrf_token);
    return fetch('/signin', {
        method: 'POST',
        credentials: 'include',
        body: form
    });
    } else {

    // Fallback to sign-in form
    }
}).then(res => {
    if (res.status === 200) {
    return res.json();
    } else {
    throw 'Auth failed';
    }
}).then(profile => {
    console.log('Auth succeeded', profile);
});

A busca personalizada será descontinuada em breve

Para determinar se você está usando uma função fetch() personalizada, faça o seguinte: verifique se ele usa um objeto PasswordCredential ou FederatedCredential. como um valor da propriedade credentials, por exemplo:

fetch('/signin', {
    method: 'POST',
    credentials: c
})

Usando uma função fetch() normal, como mostrado no exemplo de código anterior, ou usar uma XMLHttpRequest.

Até o Chrome 60, navigator.credentials.get() aceitou uma propriedade opcional do unmediated com uma sinalização booleana. Exemplo:

navigator.credentials.get({
    password: true,
    federated: {
    providers: [ 'https://accounts.google.com' ]
    },
    unmediated: true
}).then(c => {

    // Sign-in
});

A definição de unmediated: true impede que o navegador mostre o seletor de conta ao transmitir uma credencial.

A sinalização foi estendida como mediação. A mediação do usuário pode acontecer quando:

  • O usuário precisa escolher uma conta para fazer login.

  • Um usuário quer fazer login explicitamente após a chamada navigator.credentials.requireUseMediation().

Escolha uma das seguintes opções para o valor mediation:

Valor mediation Em comparação com a sinalização booleana Comportamento
silent Igual a unmediated: true A credencial foi aprovada sem mostrar um seletor de conta.
optional Igual a unmediated: false Mostra um seletor de conta se preventSilentAccess() chamado anteriormente.
required Uma nova opção Mostrar sempre um seletor de conta. Útil quando você quer permitir que um usuário mude de conta usando a caixa de diálogo do seletor de conta nativa.

Neste exemplo, a credencial é transmitida sem mostrar um seletor de conta, o equivalente da sinalização anterior, unmediated: true:

navigator.credentials.get({
    password: true,
    federated: {
    providers: [ 'https://accounts.google.com' ]
    },
    mediation: 'silent'
}).then(c => {

    // Sign-in
});

requireUserMediation() foi renomeado como preventSilentAccess().

Para se alinhar bem com a nova propriedade mediation oferecida na chamada get(), o método navigator.credentials.requireUserMediation() foi renomeado como navigator.credentials.preventSilentAccess().

O método renomeado impede a transmissão de uma credencial sem mostrar o seletor de conta (às vezes chamado sem mediação do usuário). Isso é útil quando um usuário sai de um site ou cancela a inscrição. e não queira ser conectado automaticamente na próxima visita.

signoutUser();
if (navigator.credentials) {
    navigator.credentials.preventSilentAccess();
}

Criar objetos de credenciais de forma assíncrona com o novo método navigator.credentials.create()

Agora você tem a opção de criar objetos de credenciais de forma assíncrona. com o novo método, navigator.credentials.create(). Continue lendo para conferir uma comparação entre as abordagens de sincronização e assíncrona.

Como criar um objeto PasswordCredential

Abordagem de sincronização
let c = new PasswordCredential(form);
Abordagem assíncrona (novo)
let c = await navigator.credentials.create({
    password: form
});

ou

let c = await navigator.credentials.create({
    password: {
    id: id,
    password: password
    }
});

Como criar um objeto FederatedCredential

Abordagem de sincronização
let c = new FederatedCredential({
    id:       'agektmr',
    name:     'Eiji Kitamura',
    provider: 'https://accounts.google.com',
    iconURL:  'https://*****'
});
Abordagem assíncrona (novo)
let c = await navigator.credentials.create({
    federated: {
    id:       'agektmr',
    name:     'Eiji Kitamura',
    provider: 'https://accounts.google.com',
    iconURL:  'https://*****'
    }
});

Guia de migração

Você já implementou a API Credential Management? Temos um documento com o guia de migração que você pode seguir para fazer upgrade para a nova versão.