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

Algumas das atualizações descritas aqui são explicadas na sessão Login seguro e simples: como manter os usuários engajados:

Chrome 57

O Chrome 57 introduziu essa mudança importante na 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 a API Credential Management. Por exemplo, se uma senha estiver armazenada em login.example.com, um script em www.example.com poderá mostrá-la como um dos itens de conta na caixa de diálogo do seletor de conta.

Você precisa armazenar a senha explicitamente usando navigator.credentials.store(), para que, 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 ficam visíveis para m.aliexpress.com e disponíveis para o usuário escolher:

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

Google Chrome 60

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

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

Para conferir se a API Credential Management para acesso a credenciais baseadas em senha e federadas está disponível, 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 lidar com senhas. Ele escondeu senhas do JavaScript, exigindo que os desenvolvedores enviassem o objeto PasswordCredential diretamente ao servidor para validação com uma extensão para a API fetch().

No entanto, essa abordagem introduziu várias restrições. Recebemos feedback informando que os desenvolvedores não conseguiram usar a API pelos seguintes motivos:

  • Foi preciso enviar a senha como parte de um objeto JSON.

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

Depois de realizar uma análise de segurança e reconhecer que ocultar senhas do JavaScript não impedia todos os vetores de ataque com a mesma 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 ela como texto simples. É possível usar métodos atuais para enviar informações de credenciais ao 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, verifique se ela usa um objeto PasswordCredential ou FederatedCredential como valor da propriedade credentials, por exemplo:

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

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

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

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

    // Sign-in
});

Definir unmediated: true impede que o navegador mostre o seletor de conta ao transmitir uma credencial.

A flag agora é 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 transmitida sem mostrar um seletor de conta.
optional É igual a unmediated: false Mostra um seletor de conta se preventSilentAccess() tiver sido chamado anteriormente.
required Uma nova opção Sempre mostrar um seletor de conta. Útil quando você quer permitir que um usuário troque de conta usando a caixa de diálogo seletora de conta nativa.

Neste exemplo, a credencial é transmitida sem mostrar um seletor de conta, o equivalente à 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 adequadamente à 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 a mediação do usuário). Isso é útil quando um usuário sai ou cancela a inscrição em um site e não quer fazer login novamente 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 credencial de forma assíncrona com o novo método, navigator.credentials.create(). Continue lendo para ver uma comparação entre as abordagens de sincronização e sí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

Já tem uma implementação da API Credential Management? Temos um documento do guia de migração que você pode seguir para fazer upgrade para a nova versão.