Actualizaciones más recientes de la API de administración de credenciales

Algunas de las actualizaciones que se describen aquí se explican en la sesión de Google I/O, Acceso seguro y fluido: Mantén el interés de los usuarios:

Chrome 57

Chrome 57 introdujo este importante cambio en la API de Credential Management.

Las credenciales se pueden compartir desde otro subdominio

Chrome ahora puede recuperar una credencial almacenada en un subdominio diferente mediante el API de Credential Management. Por ejemplo, si una contraseña se almacena en login.example.com, una secuencia de comandos de www.example.com puede mostrarlo como uno de los elementos de la cuenta en el diálogo del selector de cuentas.

Debes almacenar la contraseña de forma explícita con navigator.credentials.store(), para que, cuando un usuario elija una credencial presionando el diálogo, la contraseña se pasa y se copia en el origen actual.

Una vez almacenada, la contraseña está disponible como credencial con exactamente el mismo origen a partir de www.example.com.

En la siguiente captura de pantalla, la información de credenciales almacenada en login.aliexpress.com Es visible para m.aliexpress.com y el usuario puede elegir entre:

El Selector de cuentas muestra los detalles de acceso del subdominio seleccionado

Chrome 60

Chrome 60 presenta varios cambios importantes en la API de Credential Management:

La detección de funciones requiere atención

Para ver si la API de Credential Management accede Hay credenciales federadas disponibles. Verifica si window.PasswordCredential o window.FederatedCredential está disponible.

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

El objeto PasswordCredential ahora incluye contraseña

La API de Credential Management adoptó un enfoque conservador para manejar las contraseñas. Ocultó contraseñas de JavaScript, lo que requirió que los desarrolladores para enviar el objeto PasswordCredential directamente a su servidor para la validación mediante una extensión de la API de fetch().

Sin embargo, este enfoque introdujo varias restricciones. Recibimos comentarios que indican que los desarrolladores no podían usar la API por los siguientes motivos:

  • Tuvieron que enviar la contraseña como parte de un objeto JSON.

  • Tuvieron que enviar el valor hash de la contraseña a su servidor.

Después de realizar un análisis de seguridad y reconocer que ocultar de JavaScript no evitó todos los vectores de ataque con la eficacia que esperábamos, decidimos hacer un cambio.

La API de Credential Management ahora incluye una contraseña sin procesar en un objeto de credencial mostrado para que puedas acceder a él como texto sin formato. Puedes usar los métodos existentes para entregar información de credenciales a tu 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);
});

La recuperación personalizada pronto dejará de estar disponible

Para determinar si usas una función fetch() personalizada, haz lo siguiente: comprueba si usa un objeto PasswordCredential o FederatedCredential como un valor de la propiedad credentials, por ejemplo:

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

Con una función fetch() normal, como se muestra en el ejemplo de código anterior, o se recomienda usar una XMLHttpRequest.

Hasta Chrome 60, navigator.credentials.get() aceptó una propiedad opcional de unmediated con una marca booleana. Por ejemplo:

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

    // Sign-in
});

Si estableces unmediated: true, el navegador no podrá mostrar el selector de cuentas cuando se pasa una credencial.

La marca ahora se extiende como mediación. La mediación de usuarios podría ocurrir en los siguientes casos:

  • El usuario debe elegir una cuenta para acceder.

  • Un usuario quiere acceder explícitamente después de la llamada de navigator.credentials.requireUseMediation().

Elige una de las siguientes opciones para el valor mediation:

Valor mediation En comparación con la marca booleana Comportamiento
silent Es igual a unmediated: true Credencial aprobada sin mostrar un selector de cuentas.
optional Es igual a unmediated: false Muestra un selector de cuentas si preventSilentAccess() llamó anteriormente.
required Una opción nueva Mostrar siempre un selector de cuentas Es útil cuando quieres permitir que un usuario cambie de cuenta. usando el diálogo Selector de cuentas nativo.

En este ejemplo, la credencial se pasa sin mostrar un selector de cuentas el equivalente de la marca anterior, unmediated: true:

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

    // Sign-in
});

Se cambió el nombre de requireUserMediation() por preventSilentAccess()

Para alinearse bien con la nueva propiedad mediation que se ofrece en la llamada a get(), haz lo siguiente: Se cambió el nombre del método navigator.credentials.requireUserMediation() a navigator.credentials.preventSilentAccess()

El método con nombre nuevo evita que se pase una credencial sin mostrar el selector de cuentas (a veces llamado sin mediación del usuario). Esto es útil cuando un usuario sale de su cuenta en un sitio web o cancela su registro. de uno y no quiere volver a acceder automáticamente en la próxima visita.

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

Crea objetos de credenciales de forma asíncrona con el nuevo método navigator.credentials.create().

Ahora tienes la opción de crear objetos de credenciales de forma asíncrona. con el método nuevo, navigator.credentials.create(). Sigue leyendo para ver una comparación entre los enfoques síncrono y los asíncronos.

Crea un objeto PasswordCredential

Enfoque de sincronización
let c = new PasswordCredential(form);
Enfoque asíncrono (nuevo)
let c = await navigator.credentials.create({
    password: form
});

o:

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

Crea un objeto FederatedCredential

Enfoque de sincronización
let c = new FederatedCredential({
    id:       'agektmr',
    name:     'Eiji Kitamura',
    provider: 'https://accounts.google.com',
    iconURL:  'https://*****'
});
Enfoque asíncrono (nuevo)
let c = await navigator.credentials.create({
    federated: {
    id:       'agektmr',
    name:     'Eiji Kitamura',
    provider: 'https://accounts.google.com',
    iconURL:  'https://*****'
    }
});

Guía de migración

¿Tienes una implementación existente de la API de Credential Management? Tenemos un documento con la guía de migración que puedes seguir para actualizarla a la nueva versión.