Implementa una solución de identidad con FedCM del lado del proveedor de identidad

La implementación de FedCM incluye varios pasos fundamentales para el proveedor de identidad (IdP) y el grupo de confianza (RP). Consulta la documentación para obtener información sobre cómo implementar FedCM en el lado del RP.

Los IdPs deben completar los siguientes pasos para implementar FedCM:

Crea un archivo conocido

Para evitar que los rastreadores abusen de la API, se debe entregar un archivo conocido desde /.well-known/web-identity del eTLD+1 del IdP.

El archivo conocido puede incluir las siguientes propiedades:

Propiedad Obligatorio Descripción
provider_urls obligatorio Es un array de rutas de acceso a archivos de configuración de IdP. Se ignora (pero sigue siendo obligatorio) si se especifican accounts_endpoint y login_url.
accounts_endpoint Recomendado, requiere login_url
Es la URL del extremo de las cuentas. Esto permite la compatibilidad con varias configuraciones, siempre y cuando cada archivo de configuración use la misma URL de login_url y accounts_endpoint.

Nota: El parámetro es compatible con Chrome 132.
login_url Recomendado, requiere accounts_endpoint La URL de la página de acceso para que el usuario acceda al IdP. Esto permite la compatibilidad con varias configuraciones, siempre y cuando cada archivo de configuración use el mismo login_url y accounts_endpoint.

Nota: El parámetro es compatible a partir de Chrome 132 y versiones posteriores.

Por ejemplo, si los extremos del IdP se publican en https://accounts.idp.example/, también deben publicar un archivo conocido en https://idp.example/.well-known/web-identity, así como un archivo de configuración del IdP. Este es un ejemplo del contenido de un archivo conocido:

  {
    "provider_urls": ["https://accounts.idp.example/config.json"]
  }

Los IdP pueden admitir varios archivos de configuración para un IdP especificando accounts_endpoint y login_url en el archivo conocido. Esta función puede ser útil en los siguientes casos:

  • Un IdP debe admitir varias configuraciones de prueba y producción diferentes.
  • Un IdP debe admitir diferentes configuraciones por región (por ejemplo, eu-idp.example y us-idp.example).

Para admitir varios parámetros de configuración (por ejemplo, para diferenciar entre el entorno de prueba y el de producción), el IdP debe especificar accounts_endpoint y login_url:

  {
    // This property is required, but will be ignored when IdP supports
    // multiple configs (when `accounts_endpoint` and `login_url` are
    // specified), as long as `accounts_endpoint` and `login_url` in
    // that config file match those in the well-known file.
    "provider_urls": [ "https://idp.example/fedcm.json" ],

    // Specify accounts_endpoint and login_url properties to support
    // multiple config files.
    // Note: The accounts_endpoint and login_url must be identical
    // across all config files. Otherwise,
    // the configurations won't be supported.
    "accounts_endpoint": "https://idp.example/accounts",
    "login_url": "https://idp.example/login"
  }

Crea un archivo de configuración y extremos del IDP

El archivo de configuración del IDP proporciona una lista de extremos obligatorios para el navegador. Los IdPs deben alojar uno o varios archivos de configuración, y los extremos y las URLs requeridos. Todas las respuestas JSON se deben entregar con el tipo de contenido application/json.

La URL del archivo de configuración se determina según los valores proporcionados a la llamada navigator.credentials.get() que se ejecuta en un RP. El RP pasará la URL del archivo de configuración para cada proveedor de identidad:

  // Executed on RP's side:
  try {
    const credential = await navigator.credentials.get({
      identity: {
        providers: [
          {
            // To allow users to sign in with the IdP1 using FedCM, RP specifies the IdP's config file URL:
            configUrl: 'https://idp1.example/foo.json', // first IdP
            clientId: '123',
          },
          // To allow users to sign in with the IdP2 using FedCM, RP specifies the IdP's config file URL.
          // Note that multiple IdPs in a single get() are supported from Chrome 136.
          {
            configUrl: 'https://idp2.example/bar.json', // second IdP
            clientId: '456',
          },
        ],
      },
    });

    const token = credential.token;
    // Get the current IdP's configURL to identify which provider the user is signed in with
    const currentIdpConfigUrl = credential.configURL;
    if (currentIdpConfigUrl === 'https://idp1.example/foo.json') {
      // handle the case where the user signed in with idp1
    } else if (currentIdpConfigUrl === 'https://idp2.example/bar.json') {
      // handle the case where the user signed in with idp2
    }
  } catch (error) {
    // handle error
  }

El navegador recuperará el archivo de configuración con una solicitud GET sin el encabezado Origin ni el encabezado Referer. La solicitud no tiene cookies y no sigue redireccionamientos. Esto evita que el IdP sepa quién realizó la solicitud y qué RP intenta conectarse. Por ejemplo:

  GET /config.json HTTP/1.1
  Host: accounts.idp.example
  Accept: application/json
  Sec-Fetch-Dest: webidentity

El IdP debe implementar un extremo de configuración que responda con un JSON. El objeto JSON incluye las siguientes propiedades:

Propiedad Descripción
accounts_endpoint (obligatorio) Es la URL del extremo de cuentas.
account_label (opcional) Es una cadena de etiqueta de cuenta personalizada que determina qué cuentas se deben devolver cuando se usa este archivo de configuración, por ejemplo, "account_label": "developer".
Un IdP puede implementar el etiquetado de cuentas personalizado de la siguiente manera:

Por ejemplo, un IdP implementa un archivo de configuración de "https://idp.example/developer-config.json" con "account_label": "developer" especificado. El IdP también marca algunas cuentas con la etiqueta "developer" usando el parámetro label_hints en el endpoint de cuentas. Cuando un RP llama a navigator.credentials.get() con el archivo de configuración "https://idp.example/developer-config.json" especificado, solo se mostrarán las cuentas con la etiqueta "developer".

Nota: Las etiquetas de cuenta personalizadas son compatibles a partir de Chrome 132.
supports_use_other_account (opcional) Es un valor booleano que especifica si el usuario puede acceder con una cuenta diferente de la que usa actualmente (si el IdP admite varias cuentas). Esto solo se aplica al modo activo.
client_metadata_endpoint (opcional) Es la URL del extremo de metadatos del cliente.
id_assertion_endpoint (obligatorio) URL del extremo de aserción de ID.
disconnect (opcional) Es la URL del extremo de desconexión.
login_url (obligatorio) La URL de la página de acceso para que el usuario acceda al IdP.
branding (opcional) Objeto que contiene varias opciones de desarrollo de la marca.
branding.background_color (opcional) Opción de desarrollo de la marca que establece el color de fondo del botón "Continuar como…". Usa la sintaxis CSS pertinente, es decir, hex-color, hsl(), rgb() o named-color.
branding.color (opcional) Opción de desarrollo de la marca que establece el color del texto del botón "Continuar como…". Usa la sintaxis CSS pertinente, es decir, hex-color, hsl(), rgb() o named-color.
branding.icons (opcional) Es un array de objetos de íconos. Estos íconos se muestran en el diálogo de acceso. El objeto de ícono tiene dos parámetros:
  • url (obligatorio): URL de la imagen del ícono. No admite imágenes SVG.
  • size (opcional): Dimensiones del ícono, que la aplicación supone que son cuadradas y de una sola resolución. Este número debe ser mayor o igual que 25 px en modo pasivo y mayor o igual que 40 px en modo activo.

Este es un ejemplo del cuerpo de respuesta del IdP:

  {
    "accounts_endpoint": "/accounts.example",
    "client_metadata_endpoint": "/client_metadata.example",
    "id_assertion_endpoint": "/assertion.example",
    "disconnect_endpoint": "/disconnect.example",
    "login_url": "/login",
    // When RPs use this config file, only those accounts will be
    //returned that include `developer` label in the accounts endpoint.
    "account_label": "developer",
    "supports_use_other_account": true,
    "branding": {
      "background_color": "green",
      "color": "#FFEEAA",
      "icons": [{
        "url": "https://idp.example/icon.ico",
        "size": 25
      }]
    }
  }

Una vez que el navegador recupera el archivo de configuración, envía solicitudes posteriores a los extremos del IdP:

Extremos del IdP
Extremos del IdP

Usar otra cuenta

Los usuarios pueden cambiar a una cuenta diferente de la que están usando actualmente si el IdP admite varias cuentas o el reemplazo de la cuenta existente.

Para permitir que el usuario elija otras cuentas, el IdP debe especificar esta función en el archivo de configuración:

  {
    "accounts_endpoint" : "/accounts.example",
    "supports_use_other_account": true
  }

Extremo de cuentas

El extremo de cuentas del IdP devuelve una lista de las cuentas con las que el usuario accedió al IdP. Si el IdP admite varias cuentas, este extremo devolverá todas las cuentas con las que se accedió.

El navegador envía una solicitud GET con cookies con SameSite=None, pero sin un parámetro client_id, el encabezado Origin o el encabezado Referer. Esto evita de manera eficaz que el IdP sepa a qué RP intenta acceder el usuario. Por ejemplo:

  GET /accounts.example HTTP/1.1
  Host: accounts.idp.example
  Accept: application/json
  Cookie: 0x23223
  Sec-Fetch-Dest: webidentity

Cuando reciba la solicitud, el servidor debe hacer lo siguiente:

  1. Verifica que la solicitud contenga un encabezado HTTP Sec-Fetch-Dest: webidentity.
  2. Hacer coincidir las cookies de sesión con los IDs de las cuentas a las que ya se accedió
  3. Responde con la lista de cuentas.

El navegador espera una respuesta JSON que incluya una propiedad accounts con un array de información de la cuenta que tenga las siguientes propiedades:

Propiedad Descripción
id (obligatorio) Es el ID único del usuario.
name Nombre completo del usuario según su configuración regional y sus preferencias.

Nota: A partir de Chrome 141, se requiere al menos uno de los parámetros name, email, username o tel. En versiones anteriores de Chrome, se requieren name y email.
username Es el nombre de usuario que elige el usuario.

Nota: A partir de Chrome 141, se requiere al menos uno de los parámetros name, email, username o tel.
email Dirección de correo electrónico del usuario.

Nota: A partir de Chrome 141, se requiere al menos uno de los parámetros name, email, username o tel. En versiones anteriores de Chrome, se requieren name y email.
tel Número de teléfono del usuario.

Nota: A partir de Chrome 141, se requiere al menos uno de los parámetros name, email, username o tel.
picture (opcional) Es la URL de la imagen del avatar del usuario.
given_name (opcional) Nombre de pila del usuario.
approved_clients (opcional) Es un array de IDs de cliente de RP con los que se registró el usuario.
login_hints (opcional) Es un array de todos los tipos de filtros posibles que admite el IdP para especificar una cuenta. El RP puede invocar navigator.credentials.get() con la propiedad loginHint para mostrar de forma selectiva la cuenta especificada.
domain_hints (opcional) Es un array de todos los dominios con los que se asocia la cuenta. El RP puede llamar a navigator.credentials.get() con una propiedad domainHint para filtrar las cuentas.
label_hints (opcional) Es un array de etiquetas de cuenta personalizadas de cadena con las que se asocia una cuenta.
Un IdP puede implementar el etiquetado de cuentas personalizado de la siguiente manera:
  • Especifica etiquetas de la cuenta en el extremo de cuentas (con este parámetro label_hints).
  • Crea un archivo de configuración para cada etiqueta específica.

Por ejemplo, un IdP implementa el archivo de configuración https://idp.example/developer-config.json con "account_label": "developer" especificado. El IdP también marca algunas cuentas con la etiqueta "developer" usando el parámetro label_hints en el extremo de cuentas. Cuando un RP llama a navigator.credentials.get() con un archivo de configuración https://idp.example/developer-config.json especificado, solo se mostrarán las cuentas con la etiqueta "developer".

Las etiquetas de cuentas personalizadas se diferencian de la sugerencia de acceso y la sugerencia de dominio en que el servidor del IdP las mantiene por completo, y el RP solo especifica el archivo de configuración que se debe usar.

Nota: Las etiquetas de cuenta personalizadas son compatibles a partir de Chrome 132.

Ejemplo de cuerpo de respuesta:

  {
    "accounts": [{
      "id": "1234",
      "given_name": "John",
      "name": "John Doe",
      "email": "john_doe@idp.example",
      "picture": "https://idp.example/profile/123",
      // Ids of those RPs where this account can be used
      "approved_clients": ["123", "456", "789"],
      // This account has 'login_hints`. When an RP calls `navigator.credentials.get()`
      // with a `loginHint` value specified, for example, `exampleHint`, only those
      // accounts will be shown to the user whose 'login_hints' array contains the `exampleHint`.
      "login_hints": ["demo1", "exampleHint"],
      // This account is labelled. IdP can implement a specific config file for a
      // label, for example, `https://idp.example/developer-config.json`. Like that
      // RPs can filter out accounts by calling `navigator.credentials.get()` with
      // `https://idp.example/developer-config.json` config file.
      "label_hints": ["enterprise", "developer"]
    }, {
      "id": "5678",
      "given_name": "Johnny",
      "name": "Johnny",
      "email": "johnny@idp.example",
      "picture": "https://idp.example/profile/456",
      "approved_clients": ["abc", "def", "ghi"],
      "login_hints": ["demo2"],
      "domain_hints": ["@domain.example"]
    }]
  }

Si el usuario no accedió, responde con HTTP 401 (No autorizado).

El navegador consume la lista de cuentas que se devuelve y no estará disponible para el RP.

Extremo de aserción de ID

El extremo de aserción de ID del IdP devuelve una aserción para su usuario que accedió. Cuando el usuario accede a un sitio web de RP con una llamada a navigator.credentials.get(), el navegador envía una solicitud POST con cookies con SameSite=None y un tipo de contenido de application/x-www-form-urlencoded a este extremo con la siguiente información:

Propiedad Descripción
client_id (obligatorio) Es el identificador de cliente del RP.
account_id (obligatorio) Es el ID único del usuario que accede.
disclosure_text_shown Devuelve una cadena de "true" o "false" (en lugar de un valor booleano). El resultado es "false" en los siguientes casos:
  • Si no se mostró el texto de divulgación porque el ID de cliente del RP se incluyó en la lista de propiedades approved_clients de la respuesta del endpoint de cuentas.
  • Si no se mostró el texto de divulgación porque el navegador observó un momento de registro en el pasado sin la presencia de approved_clients.
  • Si el parámetro fields no incluye los tres campos (“name”, “email” y “picture”), por ejemplo, fields=[ ] o fields=['name', 'picture']. Esto es necesario para la retrocompatibilidad con implementaciones anteriores.

    Nota: A partir de Chrome 141, el texto de divulgación se puede mostrar incluso si el valor de disclosure_text_shown es "false". Para verificar si se mostró el texto de divulgación, consulta el valor de disclosure_shown_for.
disclosure_shown_for Enumera los campos que el navegador mostró al usuario en el texto de divulgación para notificarle qué datos solicita el RP al IdP.
is_auto_selected Si se realiza la reautenticación automática en el RP, is_auto_selected indica "true". En caso contrario, "false". Esto es útil para admitir más funciones relacionadas con la seguridad. Por ejemplo, algunos usuarios pueden preferir un nivel de seguridad más alto que requiera la mediación explícita del usuario en la autenticación. Si un IdP recibe una solicitud de token sin esa mediación, podría controlar la solicitud de manera diferente. Por ejemplo, devuelve un código de error para que el RP pueda volver a llamar a la API de FedCM con mediation: required.
fields (opcional) Es un array de cadenas que especifica la información del usuario que el RP solicitó que compartiera el IdP. Los siguientes campos se pueden especificar de forma opcional:
  • "name"
  • "username"
  • "email"
  • "tel"
  • "picture"
El navegador enviará fields, disclosure_text_shown y disclosure_shown_for con los campos especificados en la solicitud POST, como en el siguiente ejemplo.

Nota: La API de Fields es compatible con Chrome 132 y versiones posteriores. Los campos"username" y"tel" son compatibles a partir de Chrome 141.
params (opcional) Cualquier objeto JSON válido que permita especificar parámetros clave-valor personalizados adicionales, por ejemplo:
  • scope: Es un valor de cadena que contiene permisos adicionales que el RP debe solicitar, por ejemplo, "drive.readonly calendar.readonly".
  • nonce: Es una cadena aleatoria que proporciona el RP para garantizar que la respuesta se emita para esta solicitud específica. Evita ataques de repetición.
  • Otros parámetros personalizados de pares clave-valor.
Cuando el navegador envía una solicitud POST, el valor de params se serializará en JSON y, luego, se codificará como porcentaje.

Nota: La API de Parameters es compatible con Chrome 132 y versiones posteriores.

Ejemplo de encabezado HTTP:

  POST /assertion.example HTTP/1.1
  Host: accounts.idp.example
  Origin: https://rp.example/
  Content-Type: application/x-www-form-urlencoded
  Cookie: 0x23223
  Sec-Fetch-Dest: webidentity

  // disclosure_text_shown is set to 'false', as the 'name' field value is missing in 'fields' array
  // params value is serialized to JSON and then percent-encoded.
  account_id=123&client_id=client1234&disclosure_text_shown=false&is_auto_selected=true&params=%22%7B%5C%22nonce%5C%22%3A%5C%22nonce-value%5C%22%7D%22.%0D%0A4&fields=email,picture&disclosure_shown_for=email,picture

Cuando reciba la solicitud, el servidor debe hacer lo siguiente:

  1. Responde a la solicitud con CORS (uso compartido de recursos entre dominios).
  2. Verifica que la solicitud contenga un encabezado HTTP Sec-Fetch-Dest: webidentity.
  3. Haz coincidir el encabezado Origin con el origen de RP determinado por client_id. Rechaza si no coinciden.
  4. Compara account_id con el ID de la cuenta que ya accedió. Rechaza si no coinciden.
  5. Responde con un token. Si se rechaza la solicitud, responde con una respuesta de error.

El IdP puede decidir cómo emitir el token. En general, se firma con información como el ID de la cuenta, el ID del cliente, el origen del emisor y el nonce, de modo que el RP pueda verificar que el token sea auténtico.

El navegador espera una respuesta JSON que incluya la siguiente propiedad:

Propiedad Descripción
token Un token es una cadena que contiene declaraciones sobre la autenticación.
continue_on Es la URL de redireccionamiento que habilita un flujo de acceso de varios pasos.

El navegador pasa el token devuelto al RP para que este pueda validar la autenticación.

  {
    // IdP can respond with a token to authenticate the user
    "token": "***********"
  }

Continuar en la función

El IdP puede proporcionar una URL de redireccionamiento en la respuesta del endpoint de aserción de ID para habilitar un flujo de acceso de varios pasos. Esto es útil cuando el IdP necesita solicitar información o permisos adicionales, por ejemplo:

  • Permiso para acceder a los recursos del usuario del servidor.
  • Verificación de que la información de contacto esté actualizada
  • Controles parentales

El extremo de aserción de ID puede devolver una propiedad continue_on que incluye una ruta de acceso absoluta o relativa al extremo de aserción de ID.

  {
    // In the id_assertion_endpoint, instead of returning a typical
    // "token" response, the IdP decides that it needs the user to
    // continue on a popup window:
    "continue_on": "https://idp.example/continue_on_url"
  }

Si la respuesta contiene el parámetro continue_on, se abre una nueva ventana emergente y se dirige al usuario a la ruta de acceso especificada. Después de la interacción del usuario con la página continue_on, el IdP debe llamar a IdentityProvider.resolve() con el token que se pasó como argumento para que se pueda resolver la promesa de la llamada original a navigator.credentials.get():

  document.getElementById('example-button').addEventListener('click', async () => {
    let accessToken = await fetch('/generate_access_token.cgi');
    // Closes the window and resolves the promise (that is still hanging
    // in the relying party's renderer) with the value that is passed.
    IdentityProvider.resolve(accessToken);
  });

Luego, el navegador cerrará automáticamente la ventana emergente y devolverá el token al llamador de la API. Una llamada IdentityProvider.resolve() única es la única forma en que la ventana principal (RP) y la ventana emergente (IdP) pueden comunicarse.
Si el usuario rechaza la solicitud, el IdP puede cerrar la ventana llamando a IdentityProvider.close().

  IdentityProvider.close();

La API de Continuation requiere la interacción explícita del usuario (clics) para funcionar. Así es como funciona la API de Continuation con los diferentes modos de mediación:

  • En el modo passive, haz lo siguiente:
    • mediation: 'optional' (predeterminado): La API de Continuation solo funcionará con un gesto del usuario, como hacer clic en un botón de la página o en la IU de FedCM. Cuando se activa la reautenticación automática sin un gesto del usuario, no se abre ninguna ventana emergente y se rechaza la promesa.
    • mediation: 'required': Siempre le pide al usuario que interactúe, por lo que la API de Continuation siempre funciona.
  • En el modo activo, haz lo siguiente:
    • Siempre se requiere la activación del usuario. La API de Continuation siempre es compatible.

Si, por algún motivo, el usuario cambió su cuenta en la ventana emergente (por ejemplo, si el IdP ofrece una función para "usar otra cuenta" o en casos de delegación), la llamada de resolución toma un segundo argumento opcional que permite algo como lo siguiente:

  IdentityProvider.resolve(token, {accountId: '1234');

Devuelve una respuesta de error

El objeto id_assertion_endpoint también puede devolver una respuesta de "error", que tiene dos campos opcionales:

  • code: El IdP puede elegir uno de los errores conocidos de la lista de errores especificados de OAuth 2.0 (invalid_request, unauthorized_client, access_denied, server_error y temporarily_unavailable) o usar cualquier cadena arbitraria. En este caso, Chrome renderiza la IU de error con un mensaje de error genérico y pasa el código al RP.
  • url: Identifica una página web legible con información sobre el error para proporcionar información adicional a los usuarios. Este campo es útil para los usuarios porque los navegadores no pueden proporcionar mensajes de error enriquecidos en una IU integrada. Por ejemplo, vínculos a los próximos pasos o información de contacto del servicio de atención al cliente. Si un usuario desea obtener más información sobre los detalles del error y cómo corregirlo, puede visitar la página proporcionada desde la IU del navegador para obtener más detalles. La URL debe ser del mismo sitio que el configURL del IdP.
  // id_assertion_endpoint response
  {
    "error" : {
      "code": "access_denied",
      "url" : "https://idp.example/error?type=access_denied"
    }
  }

Etiquetas de cuenta personalizadas

Con las etiquetas de cuenta personalizadas, el IdP puede anotar las cuentas de usuario con etiquetas, y el RP puede optar por recuperar solo las cuentas con etiquetas específicas si especifica el configURL para esa etiqueta en particular. Esto puede ser útil cuando un RP necesita filtrar cuentas según criterios específicos, por ejemplo, para mostrar solo cuentas específicas de un rol, como "developer" o "hr".

Se puede realizar un filtrado similar con las funciones Sugerencia de dominio y Sugerencia de acceso, especificándolas en la llamada navigator.credentials.get(). Sin embargo, las etiquetas de cuenta personalizadas pueden filtrar usuarios especificando el archivo de configuración, lo que resulta especialmente útil cuando se usan varios configURLs. Las etiquetas de cuenta personalizadas también son diferentes, ya que se proporcionan desde el servidor del IdP, a diferencia de las sugerencias de acceso o de dominio, que se proporcionan desde el RP.

Considera un IdP que desea diferenciar entre las cuentas de "developer" y "hr". Para lograrlo, el IdP debe admitir dos URLs de configuración para "developer" y "hr", respectivamente:

  • El archivo de configuración del desarrollador https://idp.example/developer/fedcm.json tiene una etiqueta "developer", y el archivo de configuración de la empresa https://idp.example/hr/fedcm.json tiene una etiqueta "hr", como se muestra a continuación:
  // The developer config file at `https://idp.example/developer/fedcm.json`
  {
    "accounts_endpoint": "https://idp.example/accounts",
    "client_metadata_endpoint": "/client_metadata",
    "login_url": "https://idp.example/login",
    "id_assertion_endpoint": "/assertion",
    "account_label": "developer"
  }
  // The hr config file at `https://idp.example/hr/fedcm.json`
  {
    "accounts_endpoint": "https://idp.example/accounts",
    "client_metadata_endpoint": "/client_metadata",
    "login_url": "https://idp.example/login",
    "id_assertion_endpoint": "/assertion",
    "account_label": "hr"
  }
  • Con esta configuración, el archivo conocido debe incluir accounts_endpoint y login_url para permitir varias URLs de configuración:
  {
    "provider_urls": [ "https://idp.example/fedcm.json" ],
    "accounts_endpoint": "https://idp.example/accounts",
    "login_url": "https://idp.example/login"
  }
  • El endpoint de cuentas del IdP común (en este ejemplo, https://idp.example/accounts) devuelve una lista de cuentas que incluye una propiedad label_hints con etiquetas asignadas en un array para cada cuenta:
  {
  "accounts": [{
    "id": "123",
    "given_name": "John",
    "name": "John Doe",
    "email": "john_doe@idp.example",
    "picture": "https://idp.example/profile/123",
    "label_hints": ["developer"]
    }], [{
    "id": "4567",
    "given_name": "Jane",
    "name": "Jane Doe",
    "email": "jane_doe@idp.example",
    "picture": "https://idp.example/profile/4567",
    "label_hints": ["hr"]
    }]
  }

Cuando un RP quiere permitir que los usuarios de "hr" accedan, puede especificar el configURL https://idp.example/hr/fedcm.json en la llamada a navigator.credentials.get():

  let { token } = await navigator.credentials.get({
    identity: {
      providers: [{
        clientId: '1234',
        nonce: '234234',
        configURL: 'https://idp.example/hr/fedcm.json',
      },
    }
  });

Como resultado, solo el ID de la cuenta de 4567 está disponible para que el usuario acceda. El navegador oculta de forma silenciosa el ID de la cuenta de 123 para que el usuario no reciba una cuenta que no sea compatible con el IdP en este sitio.

Consideraciones adicionales:

  • Las etiquetas son cadenas. Si el array label_hints o el campo account_label usan un valor que no es una cadena, se ignorará el valor.
  • Si no se especifican etiquetas en configURL, se mostrarán todas las cuentas en el selector de cuentas de FedCM.
  • Si no se especifican etiquetas para una cuenta, esta solo se mostrará en el selector de cuentas si configURL tampoco especifica una etiqueta.
  • Si ninguna cuenta coincide con la etiqueta solicitada en el modo pasivo (similar a la función Domain Hint), el diálogo de FedCM muestra un mensaje de acceso, que permite al usuario acceder a una cuenta de IdP. En el modo activo, se abre directamente la ventana emergente de acceso.

Desconectar extremo

Cuando se invoca IdentityCredential.disconnect(), el navegador envía una solicitud POST de origen cruzado con cookies con SameSite=None y un tipo de contenido de application/x-www-form-urlencoded a este extremo de desconexión con la siguiente información:

Propiedad Descripción
account_hint Es una sugerencia para la cuenta del IdP.
client_id Es el identificador de cliente del RP.
  POST /disconnect.example HTTP/1.1
  Host: idp.example
  Origin: rp.example
  Content-Type: application/x-www-form-urlencoded
  Cookie: 0x123
  Sec-Fetch-Dest: webidentity

  account_hint=account456&client_id=rp123

Cuando reciba la solicitud, el servidor debe hacer lo siguiente:

  1. Responde a la solicitud con CORS (uso compartido de recursos entre dominios).
  2. Verifica que la solicitud contenga un encabezado HTTP Sec-Fetch-Dest: webidentity.
  3. Haz coincidir el encabezado Origin con el origen de RP determinado por client_id. Rechaza si no coinciden.
  4. Haz coincidir account_hint con los IDs de las cuentas a las que ya se accedió.
  5. Desconecta la cuenta de usuario del RP.
  6. Responder al navegador con la información de la cuenta de usuario identificada en formato JSON

Un ejemplo de carga útil de respuesta JSON se ve de la siguiente manera:

  {
    "account_id": "account456"
  }

En cambio, si el IdP desea que el navegador desconecte todas las cuentas asociadas con el RP, pasa una cadena que no coincida con ningún ID de cuenta, por ejemplo, "*".

Extremo de metadatos del cliente

El extremo de metadatos del cliente del IdP devuelve los metadatos de la parte que confía, como la política de privacidad, las condiciones del servicio y los íconos de logotipo de la RP. Los RP deben proporcionar vínculos a su política de privacidad y a sus condiciones del servicio al IdP con anticipación. Estos vínculos se muestran en el diálogo de acceso cuando el usuario aún no se registró en el RP con el IdP.

El navegador envía una solicitud GET con client_id navigator.credentials.get sin cookies. Por ejemplo:

  GET /client_metadata.example?client_id=1234 HTTP/1.1
  Host: accounts.idp.example
  Origin: https://rp.example/
  Accept: application/json
  Sec-Fetch-Dest: webidentity

Cuando reciba la solicitud, el servidor debe hacer lo siguiente:

  1. Determina el RP para client_id.
  2. Responde con los metadatos del cliente.

Las propiedades del extremo de metadatos del cliente incluyen lo siguiente:

Propiedad Descripción
privacy_policy_url (opcional) Es la URL de la política de privacidad del RP.
terms_of_service_url (opcional) Es la URL de las condiciones del servicio del RP.
icons (opcional) Es un array de objetos, como [{ "url": "https://rp.example/rp-icon.ico", "size": 40}].

El navegador espera una respuesta JSON del extremo:

  {
    "privacy_policy_url": "https://rp.example/privacy_policy.html",
    "terms_of_service_url": "https://rp.example/terms_of_service.html",
    "icons": [{
          "url": "https://rp.example/rp-icon.ico",
          "size": 40
      }]
  }

El navegador consume los metadatos del cliente que se devuelven y no estarán disponibles para el RP.

URL de acceso

Este extremo se usa para permitir que el usuario acceda al IdP.

Con la API de Login Status, el IdP debe informar el estado de acceso del usuario al navegador. Sin embargo, el estado podría no estar sincronizado, por ejemplo, cuando vence la sesión. En ese caso, el navegador puede permitir dinámicamente que el usuario acceda al IdP a través de la URL de la página de acceso especificada con el login_url del archivo de configuración del IdP.

El diálogo de FedCM muestra un mensaje que sugiere el acceso, como se muestra en la siguiente imagen.

Un diálogo de FedCM que sugiere acceder al IdP.
Un diálogo de FedCM que sugiere acceder al IdP.

Cuando el usuario hace clic en el botón Continuar, el navegador abre una ventana emergente para la página de acceso del IdP.

Ejemplo de un diálogo de FedCM.
Un ejemplo de diálogo que se muestra después de hacer clic en el botón para acceder al IdP.

El diálogo es una ventana normal del navegador que tiene cookies propias. Lo que sucede dentro del diálogo depende del IdP, y no hay identificadores de ventanas disponibles para realizar una solicitud de comunicación entre orígenes a la página del RP. Después de que el usuario accede, el IdP debe hacer lo siguiente:

  • Envía el encabezado Set-Login: logged-in o llama a la API de navigator.login.setStatus("logged-in") para informar al navegador que el usuario accedió.
  • Llama a IdentityProvider.close() para cerrar el diálogo.
Un usuario accede a un RP después de acceder al IdP con FedCM.

Informa al navegador sobre el estado de acceso del usuario

La API de estado de acceso es un mecanismo por el cual un sitio web, en especial un IdP, informa al navegador el estado de acceso del usuario en el IdP. Con esta API, el navegador puede reducir las solicitudes innecesarias al IdP y mitigar posibles ataques de sincronización.

Los IdP pueden indicar el estado de acceso del usuario al navegador enviando un encabezado HTTP o llamando a una API de JavaScript cuando el usuario accede al IdP o cuando sale de todas sus cuentas de IdP. Para cada IdP (identificado por su URL de configuración), el navegador mantiene una variable de tres estados que representa el estado de acceso con los siguientes valores posibles:

  • logged-in
  • logged-out
  • unknown (predeterminada)
Estado de acceso Descripción
logged-in Cuando el estado de acceso del usuario se establece en logged-in, el RP que llama a FedCM realiza solicitudes al endpoint de cuentas del IdP y muestra las cuentas disponibles al usuario en el diálogo de FedCM.
logged-out Cuando el estado de acceso del usuario es logged-out, la llamada a FedCM falla de forma silenciosa sin realizar una solicitud al endpoint de cuentas del IdP.
unknown (predeterminada) El estado unknown se establece antes de que el IdP envíe un indicador con la API de Login Status. Cuando el estado es unknown, el navegador realiza una solicitud al extremo de cuentas del IdP y actualiza el estado según la respuesta del extremo de cuentas.

Para indicar que el usuario accedió, envía un encabezado HTTP Set-Login: logged-in en una solicitud de navegación de nivel superior o de subrecurso del mismo sitio en el origen del IdP:

  Set-Login: logged-in

También puedes llamar al método JavaScript navigator.login.setStatus('logged-in') desde el origen del IdP en una navegación de nivel superior:

  navigator.login.setStatus('logged-in')

El estado de acceso del usuario se establecerá como logged-in.

Para indicar que el usuario salió de todas sus cuentas, envía un encabezado HTTP Set-Login: logged-out en una navegación de nivel superior o en una solicitud de subrecurso del mismo sitio en el origen del IdP:

  Set-Login: logged-out

Como alternativa, llama a la API de JavaScript navigator.login.setStatus('logged-out') desde el origen del IdP en una navegación de nivel superior:

  navigator.login.setStatus('logged-out')

El estado de acceso del usuario se establecerá como logged-out.

El estado unknown se establece antes de que el IdP envíe un indicador con la API de Login Status. El navegador realiza una solicitud al extremo de cuentas del IdP y actualiza el estado según la respuesta del extremo de cuentas:

  • Si el extremo devuelve una lista de cuentas activas, actualiza el estado a logged-in y abre el diálogo de FedCM para mostrar esas cuentas.
  • Si el extremo no devuelve ninguna cuenta, actualiza el estado a logged-out y haz que falle la llamada a FedCM.

Permite que el usuario acceda a través de un flujo de acceso dinámico

Aunque el IdP sigue informando el estado de acceso del usuario al navegador, podría no estar sincronizado, por ejemplo, cuando vence la sesión. El navegador intenta enviar una solicitud con credenciales al endpoint de cuentas cuando el estado de acceso es logged-in, pero el servidor no devuelve ninguna cuenta porque la sesión ya no está disponible. En ese caso, el navegador puede permitir dinámicamente que el usuario acceda al IdP a través de una ventana emergente.

Pasos siguientes

Implementa FedCM para tus RP y distribuye el SDK de JavaScript. Mantén los RP actualizados, ya que elimina la necesidad de la autoimplementación.
Aprende a configurar tu entorno y depurar tu implementación.