Algumas das atualizações descritas aqui são explicadas na sessão do Google I/O, Login seguro e perfeito: 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
Credential Management API.
Por exemplo, se uma senha for armazenada em login.example.com
,
um script em www.example.com
poderá mostrá-la como um dos itens da conta na caixa de diálogo do seletor de contas.
É necessário 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 seja transmitida e copiada para a origem atual.
Depois de armazenada, a senha fica disponível como uma credencial
na mesma origem www.example.com
.
Na captura de tela abaixo, as informações de credencial armazenadas em login.aliexpress.com
são visíveis para m.aliexpress.com
e disponíveis para o usuário escolher:
Chrome 60
O Chrome 60 introduz várias mudanças importantes na API Credential Management:
Como a função
fetch()
personalizada não é mais necessária para buscar a senha, ela será descontinuada em breve.navigator.credentials.get()
agora aceita um tipo enumeradomediation
em vez de uma flag booleanaunmediated
.requireUserMediation()
foi renomeado comopreventSilentAccess()
.O novo método
navigator.credentials.create()
cria objetos de credencial de forma assíncrona.
A detecção de recursos precisa de atenção
Para saber se a API Credential Management para acessar credenciais com base em senha e
federadas está disponível, verifique se window.PasswordCredential
ou
window.FederatedCredential
estão disponíveis.
if (window.PasswordCredential || window.FederatedCredential) {
// The Credential Management API is available
}
O objeto PasswordCredential
agora inclui a senha
A API Credential Management adotou uma abordagem conservadora para o processamento de senhas.
Ele ocultava senhas do JavaScript, exigindo que os desenvolvedores
enviassem o objeto PasswordCredential
diretamente para o servidor
para validação usando uma extensão da API fetch()
.
No entanto, essa abordagem introduziu várias restrições. Recebemos feedback de que os desenvolvedores não conseguiam usar a API porque:
Eles precisavam 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 o ocultamento de senhas do JavaScript não impedia todos os vetores de ataque com a eficácia esperada, 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. Você pode usar métodos existentes para enviar informações de credencial ao 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,
confira se ela usa um objeto PasswordCredential
ou FederatedCredential
como um valor da propriedade credentials
, por exemplo:
fetch('/signin', {
method: 'POST',
credentials: c
})
É recomendável usar uma função fetch()
regular, conforme mostrado no exemplo de código anterior,
ou usar um XMLHttpRequest
.
navigator.credentials.get()
agora aceita uma mediação de tipo enumerado
Até o Chrome 60,
navigator.credentials.get()
aceitava uma propriedade unmediated
opcional
com uma flag booleana. Exemplo:
navigator.credentials.get({
password: true,
federated: {
providers: [ 'https://accounts.google.com' ]
},
unmediated: true
}).then(c => {
// Sign-in
});
A configuração 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 |
Comparado com a flag booleana | Comportamento | |
---|---|---|---|
silent |
Igual a unmediated: true |
A credencial foi transmitida sem mostrar um seletor de contas. | |
optional |
Igual a unmediated: false |
Mostra um seletor de contas se
preventSilentAccess() for chamado anteriormente. |
|
required |
Uma nova opção | Sempre mostrar um seletor de contas. Útil quando você quer permitir que um usuário troque de conta usando a caixa de diálogo nativa do seletor de contas. |
Neste exemplo,
a credencial é transmitida sem mostrar um seletor de conta,
o equivalente da flag 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 à 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 de mediação do usuário). Isso é útil quando um usuário faz logout de um site ou cancela o registro e não quer fazer login automaticamente na próxima visita.
signoutUser();
if (navigator.credentials) {
navigator.credentials.preventSilentAccess();
}
Criar objetos de credencial 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()
.
Confira a seguir uma comparação entre as abordagens síncrona e assíncrona.
Como criar um objeto PasswordCredential
Abordagem de sincronização
let c = new PasswordCredential(form);
Abordagem assíncrona (nova)
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 (nova)
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 de guia de migração que você pode seguir para fazer upgrade para a nova versão.