Implémenter une solution d'identité avec FedCM côté fournisseur d'identité

L'implémentation de la FedCM comprend plusieurs étapes de base pour le fournisseur d'identité (IdP) et la partie de confiance (RP). Consultez la documentation pour découvrir comment implémenter FedCM du côté du RP.

Pour implémenter FedCM, les IdPs doivent suivre les étapes suivantes:

Créer un fichier well-known

Pour empêcher les traceurs d'utiliser abusivement l'API, un fichier well-known doit être diffusé à partir de /.well-known/web-identity de l'eTLD+1 de l'IDP.

Le fichier connu peut inclure les propriétés suivantes:

Propriété Requis Description
provider_urls required Tableau de chemins d'accès aux fichiers de configuration de l'IDP. Ignoré (mais toujours obligatoire) si accounts_endpoint et login_url sont spécifiés.
accounts_endpoint recommandé, nécessite login_url
URL du point de terminaison des comptes. Cela permet de prendre en charge plusieurs configurations, à condition que chaque fichier de configuration utilise la même URL login_url et accounts_endpoint.

Remarque: Le paramètre est compatible avec Chrome 132 et versions ultérieures.
login_url recommandé, nécessite accounts_endpoint URL de la page de connexion permettant à l'utilisateur de se connecter à l'IDP. Cela permet de prendre en charge plusieurs configurations, à condition que chaque fichier de configuration utilise les mêmes login_url et accounts_endpoint.

Remarque: Le paramètre est compatible à partir de Chrome 132 ou version ultérieure.

Par exemple, si les points de terminaison de l'IdP sont diffusés sous https://accounts.idp.example/, ils doivent diffuser un fichier well-known à https://idp.example/.well-known/web-identity, ainsi qu'un fichier de configuration de l'IdP. Voici un exemple de contenu de fichier connu:

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

Les IdP peuvent accepter plusieurs fichiers de configuration pour un IdP, en spécifiant accounts_endpoint et login_url dans le fichier well-known.
Cette fonctionnalité peut être utile dans les cas suivants:

  • Un IdP doit prendre en charge plusieurs configurations de test et de production différentes.
  • Un IdP doit prendre en charge différentes configurations par région (par exemple, eu-idp.example et us-idp.example).

Pour prendre en charge plusieurs configurations (par exemple, pour différencier l'environnement de test de l'environnement de production), l'IDP doit spécifier accounts_endpoint et 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"
  }

Créer un fichier de configuration de l'IDP et des points de terminaison

Le fichier de configuration de l'IDP fournit une liste des points de terminaison requis pour le navigateur. Les IdP doivent héberger un ou plusieurs fichiers de configuration, ainsi que les points de terminaison et les URL requis. Toutes les réponses JSON doivent être diffusées avec le type de contenu application/json.

L'URL du fichier de configuration est déterminée par les valeurs fournies à l'appel navigator.credentials.get() exécuté sur un RP.

  const credential = await navigator.credentials.get({
    identity: {
      context: 'signup',
      providers: [{
        configURL: 'https://accounts.idp.example/config.json',
        clientId: '********',
        nonce: '******'
      }]
    }
  });
  const { token } = credential;

Le RP transmet l'URL du fichier de configuration à l'appel de l'API FedCM pour permettre à l'utilisateur de se connecter:

  // Executed on RP's side:
  const credential = await navigator.credentials.get({
    identity: {
      context: 'signup',
      providers: [{
        // To allow users to sign in with an IdP using FedCM, RP specifies the IdP's config file URL:
        configURL: 'https://accounts.idp.example/fedcm.json',
        clientId: '********',
  });
  const { token } = credential;

Le navigateur récupère le fichier de configuration avec une requête GET sans l'en-tête Origin ni l'en-tête Referer. La requête ne contient pas de cookies et ne suit pas les redirections. Cela empêche efficacement l'IDP d'apprendre qui a effectué la requête et quel RP tente de se connecter. Exemple :

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

L'IDP doit implémenter un point de terminaison de configuration qui répond avec un JSON. Le fichier JSON inclut les propriétés suivantes:

Propriété Description
accounts_endpoint (obligatoire) URL du point de terminaison des comptes.
accounts.include (facultatif) Chaîne de libellé de compte personnalisée, qui détermine les comptes à renvoyer lorsque ce fichier de configuration est utilisé (par exemple, "accounts": {"include": "developer"}).
Un IdP peut implémenter le libellé de compte personnalisé comme suit:

Par exemple, un IdP implémente le fichier de configuration "https://idp.example/developer-config.json" avec "accounts": {"include": "developer"} spécifié. Le fournisseur d'identité marque également certains comptes avec l'étiquette "developer" à l'aide du paramètre labels dans le point de terminaison des comptes. Lorsqu'un RP appelle navigator.credentials.get() avec le fichier de configuration "https://idp.example/developer-config.json" spécifié, seuls les comptes associés au libellé "developer" sont renvoyés.

Remarque: Les libellés de compte personnalisés sont compatibles à partir de Chrome 132.
client_metadata_endpoint (facultatif) URL du point de terminaison des métadonnées client.
id_assertion_endpoint (obligatoire) URL du point de terminaison d'assertion d'identité.
disconnect (facultatif) URL du point de terminaison de déconnexion.
login_url (obligatoire) URL de la page de connexion permettant à l'utilisateur de se connecter à l'IDP.
branding (facultatif) Objet contenant différentes options de branding.
branding.background_color (facultatif) Option de branding qui définit la couleur d'arrière-plan du bouton "Continuer en tant que…". Utilisez la syntaxe CSS appropriée, à savoir hex-color, hsl(), rgb() ou named-color.
branding.color (facultatif) Option de branding qui définit la couleur du texte du bouton "Continuer en tant que…". Utilisez la syntaxe CSS appropriée, à savoir hex-color, hsl(), rgb() ou named-color.
branding.icons (facultatif) Tableau d'objets d'icônes. Ces icônes s'affichent dans la boîte de dialogue de connexion. L'objet icône comporte deux paramètres :
  • url (obligatoire): URL de l'image de l'icône. Les images SVG ne sont pas compatibles.
  • size (facultatif): dimensions de l'icône, supposées être carrées et à résolution unique par l'application. Ce nombre doit être supérieur ou égal à 25 px en mode passif et supérieur ou égal à 40 px en mode actif.
modes Objet contenant des spécifications sur l'affichage de l'UI FedCM dans différents modes:
  • active
  • passive
modes.active Objet contenant des propriétés permettant de personnaliser le comportement de FedCM dans un mode spécifique. modes.active et modes.passive peuvent tous deux contenir le paramètre suivant:
  • supports_use_other_account: valeur booléenne indiquant si l'utilisateur peut se connecter avec un compte différent de celui avec lequel il est actuellement connecté (si l'IDP prend en charge plusieurs comptes).

Remarque: La fonctionnalité Utiliser un autre compte et le mode actif sont compatibles à partir de Chrome 132.
modes.passive

Voici un exemple de corps de réponse de l'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.
    "accounts": {"include": "developer"},
    "modes": {
        "active": {
          "supports_use_other_account": true,
        }
    },
    "branding": {
      "background_color": "green",
      "color": "#FFEEAA",
      "icons": [{
        "url": "https://idp.example/icon.ico",
        "size": 25
      }]
    }
  }

Une fois que le navigateur a récupéré le fichier de configuration, il envoie les requêtes suivantes aux points de terminaison de l'IDP:

Points de terminaison de l'IDP
Points de terminaison de l'IDP

Utiliser un autre compte

Les utilisateurs peuvent passer à un compte différent de celui avec lequel ils sont actuellement connectés, si l'IDP prend en charge plusieurs comptes ou remplace le compte existant.

Pour permettre à l'utilisateur de choisir d'autres comptes, l'IDP doit spécifier cette fonctionnalité dans le fichier de configuration:

  {
    "accounts_endpoint" : "/accounts.example",
    "modes": {
      "active": {
        // Allow the user to choose other account (false by default)
        "supports_use_other_account": true
      }
      // "passive" mode can be configured separately
    }
  }

Point de terminaison des comptes

Le point de terminaison des comptes de l'IDP renvoie la liste des comptes auxquels l'utilisateur est connecté sur l'IDP. Si l'IDP accepte plusieurs comptes, ce point de terminaison renvoie tous les comptes connectés.

Le navigateur envoie une requête GET avec des cookies avec SameSite=None, mais sans paramètre client_id, en-tête Origin ou en-tête Referer. Cela empêche efficacement l'IdP d'apprendre à quel RP l'utilisateur tente de se connecter. Exemple :

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

À la réception de la requête, le serveur doit:

  1. Vérifiez que la requête contient un en-tête HTTP Sec-Fetch-Dest: webidentity.
  2. Faites correspondre les cookies de session aux ID des comptes déjà connectés.
  3. Répondez avec la liste des comptes.

Le navigateur attend une réponse JSON qui inclut une propriété accounts avec un tableau d'informations de compte avec les propriétés suivantes:

Propriété Description
id (obligatoire) Identifiant unique de l'utilisateur.
name (obligatoire) Prénom et nom de famille de l'utilisateur.
email (obligatoire) Adresse e-mail de l'utilisateur.
given_name (facultatif) Prénom de l'utilisateur.
picture (facultatif) URL de l'image de l'avatar de l'utilisateur.
approved_clients (facultatif) Tableau d'ID client RP avec lesquels l'utilisateur s'est enregistré.
login_hints (facultatif) Tableau de tous les types de filtres possibles compatibles avec l'IDP pour spécifier un compte. Le RP peut appeler navigator.credentials.get() avec la propriété loginHint pour afficher de manière sélective le compte spécifié.
domain_hints (facultatif) Tableau de tous les domaines auxquels le compte est associé. Le RP peut appeler navigator.credentials.get() avec une propriété domainHint pour filtrer les comptes.
labels (facultatif) Tableau de chaînes de libellés de compte personnalisés auxquels un compte est associé.
Un IdP peut implémenter le libellé de compte personnalisé comme suit:
  • Spécifiez des libellés de compte dans le point de terminaison des comptes (à l'aide de ce paramètre labels).
  • Créez un fichier de configuration pour chaque libellé spécifique.

Par exemple, un IdP implémente le fichier de configuration https://idp.example/developer-config.json avec "accounts": {"include": "developer"} spécifié. Le fournisseur d'identité marque également certains comptes avec l'étiquette "developer" à l'aide du paramètre labels dans le point de terminaison des comptes. Lorsqu'un RP appelle navigator.credentials.get() avec le fichier de configuration https://idp.example/developer-config.json spécifié, seuls les comptes associés au libellé "developer" sont renvoyés.

Les libellés de compte personnalisés sont différents de l'indice de connexion et de l'indice de domaine, car ils sont entièrement gérés par le serveur du fournisseur d'identité, et le RP ne spécifie que le fichier de configuration à utiliser.

Remarque: Les libellés de compte personnalisés sont compatibles à partir de Chrome 132.

Exemple de corps de réponse:

  {
    "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.
      "labels": ["hr", "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 l'utilisateur n'est pas connecté, répondez avec HTTP 401 (Non autorisé).

La liste des comptes renvoyée est utilisée par le navigateur et n'est pas disponible pour le RP.

Point de terminaison d'assertion d'identité

Le point de terminaison d'assertion d'identité de l'IdP renvoie une assertion pour son utilisateur connecté. Lorsque l'utilisateur se connecte à un site Web de RP à l'aide de l'appel navigator.credentials.get(), le navigateur envoie une requête POST avec des cookies avec SameSite=None et un type de contenu application/x-www-form-urlencoded à ce point de terminaison avec les informations suivantes:

Propriété Description
client_id (obligatoire) Identifiant client de l'RP.
account_id (obligatoire) Identifiant unique de l'utilisateur qui se connecte.
disclosure_text_shown Résultats sous forme de chaîne "true" ou "false" (plutôt que sous forme de valeur booléenne). Le résultat est "false" dans les cas suivants:
  • Si le texte d'information n'a pas été affiché, car l'ID client du RP était inclus dans la liste de propriétés approved_clients de la réponse du point de terminaison accounts.
  • Si le texte d'information n'a pas été affiché, car le navigateur a observé un moment d'inscription dans le passé en l'absence de approved_clients.
  • Si le paramètre fields n'inclut pas un ou plusieurs des trois champs ("name", "email" et "picture"), par exemple, fields=[ ] ou fields=['name', 'picture']. Cela est nécessaire pour la rétrocompatibilité avec les anciennes implémentations d'IDP qui s'attendent à ce qu'une chaîne de divulgation inclue toujours les trois champs.
is_auto_selected Si la réauthentification automatique est effectuée sur le RP, is_auto_selected indique "true". Sinon, il est défini sur "false". Cela permet de prendre en charge davantage de fonctionnalités liées à la sécurité. Par exemple, certains utilisateurs peuvent préférer un niveau de sécurité plus élevé qui nécessite une médiation explicite de l'utilisateur lors de l'authentification. Si un IdP reçoit une requête de jeton sans cette médiation, il peut traiter la requête différemment. Par exemple, renvoyez un code d'erreur afin que le RP puisse à nouveau appeler l'API FedCM avec mediation: required.
fields (facultatif) Tableau de chaînes qui spécifie les informations utilisateur ("name", "email", "picture") que l'RP doit demander à l'IdP de partager avec lui.
Le navigateur envoie fields, disclosure_text_shown et disclosure_shown_for en listant les champs spécifiés dans la requête POST, comme dans l'exemple suivant.

Remarque: Le paramètre "Fields" est compatible avec Chrome 132 et versions ultérieures.
params (facultatif) Tout objet JSON valide permettant de spécifier des paramètres clé-valeur personnalisés supplémentaires, par exemple :
  • scope: valeur de chaîne contenant des autorisations supplémentaires que le RP doit demander, par exemple "drive.readonly calendar.readonly"
  • nonce: chaîne aléatoire fournie par le RP pour s'assurer que la réponse est émise pour cette requête spécifique. Empêche les attaques par rejeu.
  • Autres paramètres de clé-valeur personnalisés.
Lorsque le navigateur envoie une requête POST, la valeur params est sérialisée au format JSON, puis encodée en pourcentage.

Remarque: L'API Parameters est compatible avec Chrome 132 et versions ultérieures.

Exemple d'en-tête 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&disclosure_text_shown=true&fields=email,picture&disclosure_shown_for=email,picture

À la réception de la requête, le serveur doit:

  1. Répondez à la requête avec le partage de ressources entre origines (CORS).
  2. Vérifiez que la requête contient un en-tête HTTP Sec-Fetch-Dest: webidentity.
  3. Faites correspondre l'en-tête Origin à l'origine du RP déterminée par client_id. Refusez-les si elles ne correspondent pas.
  4. Faites correspondre account_id à l'ID du compte déjà connecté. Refusez-les si elles ne correspondent pas.
  5. Répondez avec un jeton. Si la requête est rejetée, répondez par une réponse d'erreur.

L'IDP peut décider de la manière dont il émet le jeton. En général, il est signé avec des informations telles que l'ID de compte, l'ID client, l'origine de l'émetteur et le nonce, afin que la RP puisse vérifier que le jeton est authentique.

Le navigateur attend une réponse JSON qui inclut la propriété suivante:

Propriété Description
token Un jeton est une chaîne qui contient des revendications concernant l'authentification.
continue_on URL de redirection permettant d'effectuer une procédure de connexion en plusieurs étapes.

Le jeton renvoyé est transmis au RP par le navigateur afin que le RP puisse valider l'authentification.

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

Continuer sur la fonctionnalité

Le fournisseur d'identité peut fournir une URL de redirection dans la réponse du point de terminaison d'assertion d'identité pour activer un flux de connexion en plusieurs étapes. Cela est utile lorsque l'IDP doit demander des informations ou des autorisations supplémentaires, par exemple:

  • Autorisation d'accéder aux ressources côté serveur de l'utilisateur.
  • Vérification que les coordonnées sont à jour
  • Contrôle parental.

Le point de terminaison d'assertion d'identité peut renvoyer une propriété continue_on qui inclut un chemin absolu ou relatif vers le point de terminaison d'assertion d'identité.

  {
    // 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 réponse contient le paramètre continue_on, une nouvelle fenêtre pop-up s'ouvre et redirige l'utilisateur vers le chemin d'accès spécifié. Une fois que l'utilisateur a interagi avec la page continue_on, l'IDP doit appeler IdentityProvider.resolve() avec le jeton transmis en tant qu'argument afin que la promesse de l'appel navigator.credentials.get() d'origine puisse être résolue:

  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);
  });

Le navigateur ferme alors automatiquement le pop-up et renvoie le jeton à l'appelant de l'API. Un appel IdentityProvider.resolve() unique est le seul moyen pour la fenêtre parente (RP) et la fenêtre pop-up (IdP) de communiquer.
Si l'utilisateur refuse la requête, l'IDP peut fermer la fenêtre en appelant IdentityProvider.close().

  IdentityProvider.close();

Pour fonctionner, l'API Continuation nécessite une interaction explicite de l'utilisateur (clics). Voici comment l'API Continuation fonctionne avec différents modes de médiation:

  • En mode passif :
    • mediation: 'optional' (par défaut): l'API Continuation ne fonctionne qu'avec un geste utilisateur, tel que cliquer sur un bouton sur la page ou dans l'interface utilisateur FedCM. Lorsque la réauthentification automatique est déclenchée sans geste de l'utilisateur, aucune fenêtre pop-up ne s'ouvre et la promesse est rejetée.
    • mediation: 'required': demande toujours à l'utilisateur d'interagir, de sorte que l'API Continuation fonctionne toujours.
  • En mode actif :
    • L'activation de l'utilisateur est toujours requise. L'API Continuation est compatible.

Si, pour une raison quelconque, l'utilisateur a modifié son compte dans le pop-up (par exemple, si l'IDP propose une fonction "Utiliser un autre compte" ou en cas de délégation), l'appel de résolution prend un deuxième argument facultatif permettant quelque chose comme:

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

Renvoyez une réponse d'erreur.

id_assertion_endpoint peut également renvoyer une réponse "error", qui comporte deux champs facultatifs:

  • code: l'IdP peut choisir l'une des erreurs connues de la liste d'erreurs spécifiée par OAuth 2.0 (invalid_request, unauthorized_client, access_denied, server_error et temporarily_unavailable) ou utiliser une chaîne arbitraire. Dans ce cas, Chrome affiche l'UI d'erreur avec un message d'erreur générique et transmet le code au RP.
  • url: identifie une page Web lisible par l'utilisateur avec des informations sur l'erreur pour fournir des informations supplémentaires aux utilisateurs. Ce champ est utile aux utilisateurs, car les navigateurs ne peuvent pas fournir de messages d'erreur riches dans une UI intégrée. (par exemple, des liens vers les prochaines étapes ou les coordonnées du service client) Si un utilisateur souhaite en savoir plus sur les détails de l'erreur et sur la façon de la corriger, il peut consulter la page fournie depuis l'interface utilisateur du navigateur. L'URL doit être du même site que l'configURL de l'IDP.
  // id_assertion_endpoint response
  {
    "error" : {
      "code": "access_denied",
      "url" : "https://idp.example/error?type=access_denied"
    }
  }

Libellés de compte personnalisés

Avec les libellés de compte personnalisés, l'IDP peut annoter les comptes utilisateur avec des libellés, et le RP peut choisir de n'extraire que les comptes avec des libellés spécifiques en spécifiant le configURL pour ce libellé spécifique. Cela peut être utile lorsqu'un RP doit filtrer les comptes en fonction de critères spécifiques, par exemple pour n'afficher que les comptes spécifiques aux rôles tels que "developer" ou "hr".

Un filtrage similaire est possible à l'aide des fonctionnalités Invite de domaine et Invite de connexion, en les spécifiant dans l'appel navigator.credentials.get(). Toutefois, les libellés de compte personnalisés peuvent filtrer les utilisateurs en spécifiant le fichier de configuration, ce qui est particulièrement utile lorsque plusieurs configURLs sont utilisés. Les libellés de compte personnalisés sont également différents en ce sens qu'ils sont fournis par le serveur d'IDP, et non par le RP, comme les indications de connexion ou de domaine.

Prenons l'exemple d'un IdP qui souhaite différencier les comptes "developer" et "hr". Pour ce faire, l'IDP doit prendre en charge deux configURL pour "developer" et "hr", respectivement:

  • Le fichier de configuration du développeur https://idp.example/developer/fedcm.json comporte un libellé "developer", et le fichier de configuration de l'entreprise https://idp.example/hr/fedcm.json comporte un libellé "hr" comme suit:
  // 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",
    "accounts": {
      // Account label
      "include": "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",
    "accounts": {
      // Account label
      "include": "hr"
    }
  }
  • Avec une telle configuration, le fichier well-known doit inclure accounts_endpoint et login_url pour autoriser plusieurs configURLs:
  {
    "provider_urls": [ "https://idp.example/fedcm.json" ],
    "accounts_endpoint": "https://idp.example/accounts",
    "login_url": "https://idp.example/login"
  }
  • Le point de terminaison des comptes de l'IDP commun (https://idp.example/accounts dans cet exemple) renvoie une liste de comptes incluant une propriété labels avec des libellés attribués dans un tableau pour chaque compte:
  {
  "accounts": [{
    "id": "123",
    "given_name": "John",
    "name": "John Doe",
    "email": "john_doe@idp.example",
    "picture": "https://idp.example/profile/123",
    "labels": ["developer"]
    }], [{
    "id": "4567",
    "given_name": "Jane",
    "name": "Jane Doe",
    "email": "jane_doe@idp.example",
    "picture": "https://idp.example/profile/4567",
    "labels": ["hr"]
    }]
  }

Lorsqu'un RP souhaite autoriser les utilisateurs "hr" à se connecter, il peut spécifier la valeur https://idp.example/hr/fedcm.json configURL dans l'appel navigator.credentials.get():

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

Par conséquent, seul l'ID de compte 4567 est disponible pour que l'utilisateur puisse se connecter. L'ID de compte 123 est masqué de manière silencieuse par le navigateur afin que l'utilisateur ne reçoive pas de compte non compatible avec l'IDP sur ce site.

  • Les libellés sont des chaînes. Si le tableau labels ou le champ include contient un élément qui n'est pas une chaîne, il est ignoré.
  • Si aucun libellé n'est spécifié dans configURL, tous les comptes s'affichent dans le sélecteur de compte FedCM.
  • Si aucun libellé n'est spécifié pour un compte, il ne s'affiche dans le sélecteur de comptes que si configURL ne spécifie pas non plus de libellé.
  • Si aucun compte ne correspond au libellé demandé en mode passif (comme la fonctionnalité d'indice de domaine), la boîte de dialogue FedCM affiche une invite de connexion, qui permet à l'utilisateur de se connecter à un compte de fournisseur d'identité. Pour le mode actif, la fenêtre pop-up de connexion s'ouvre directement.

Déconnecter un point de terminaison

En appelant IdentityCredential.disconnect(), le navigateur envoie une requête POST inter-origine avec des cookies avec SameSite=None et un type de contenu application/x-www-form-urlencoded à ce point de terminaison de déconnexion avec les informations suivantes:

Propriété Description
account_hint Indice pour le compte IdP.
client_id Identifiant client de l'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

À la réception de la requête, le serveur doit:

  1. Répondez à la requête avec le partage de ressources entre origines (CORS).
  2. Vérifiez que la requête contient un en-tête HTTP Sec-Fetch-Dest: webidentity.
  3. Faites correspondre l'en-tête Origin à l'origine du RP déterminée par client_id. Refusez-les si elles ne correspondent pas.
  4. Faites correspondre account_hint aux ID des comptes déjà connectés.
  5. Déconnectez le compte utilisateur du RP.
  6. Répondez au navigateur avec les informations du compte utilisateur identifié au format JSON.

Voici un exemple de charge utile JSON de réponse:

  {
    "account_id": "account456"
  }

Au lieu de cela, si l'IDP souhaite que le navigateur dissocie tous les comptes associés à l'RP, transmettez une chaîne qui ne correspond à aucun ID de compte, par exemple "*".

Point de terminaison des métadonnées client

Le point de terminaison des métadonnées client de l'IDP renvoie les métadonnées de la partie de confiance, telles que ses règles de confidentialité, ses conditions d'utilisation et ses icônes de logo. Les RP doivent fournir à l'IDP à l'avance des liens vers leurs règles de confidentialité et leurs conditions d'utilisation. Ces liens s'affichent dans la boîte de dialogue de connexion lorsque l'utilisateur ne s'est pas encore inscrit sur le RP auprès de l'IDP.

Le navigateur envoie une requête GET à l'aide de client_id navigator.credentials.get sans cookies. Exemple :

  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

À la réception de la requête, le serveur doit:

  1. Déterminez le RP pour client_id.
  2. Répondez avec les métadonnées du client.

Les propriétés du point de terminaison des métadonnées client incluent:

Propriété Description
privacy_policy_url (facultatif) URL des règles de confidentialité de la RP.
terms_of_service_url (facultatif) URL des conditions d'utilisation de la RP.
icons (facultatif) Tableau d'objets, tels que [{ "url": "https://rp.example/rp-icon.ico", "size": 40}]

Le navigateur s'attend à recevoir une réponse JSON du point de terminaison:

  {
    "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
      }]
  }

Les métadonnées client renvoyées sont consommées par le navigateur et ne sont pas disponibles pour le RP.

URL de connexion

Ce point de terminaison permet à l'utilisateur de se connecter à l'IDP.

Avec l'API Login Status, l'IDP doit informer le navigateur de l'état de connexion de l'utilisateur. Toutefois, l'état peut être désynchronisé, par exemple lorsque la session expire. Dans ce cas, le navigateur peut autoriser l'utilisateur à se connecter dynamiquement à l'IDP via l'URL de la page de connexion spécifiée avec le login_url du fichier de configuration de l'IDP.

La boîte de dialogue FedCM affiche un message suggérant une connexion, comme illustré dans l'image suivante.

A
Boîte de dialogue FedCM suggérant de se connecter au fournisseur d'identité.

Lorsque l'utilisateur clique sur le bouton Continuer, le navigateur ouvre une fenêtre pop-up pour la page de connexion de l'IDP.

Exemple de boîte de dialogue FedCM.
Exemple de boîte de dialogue affichée après avoir cliqué sur le bouton de connexion à l'IDP.

La boîte de dialogue est une fenêtre de navigateur standard contenant des cookies propriétaires. Tout ce qui se passe dans la boîte de dialogue dépend de l'IDP, et aucune poignée de fenêtre n'est disponible pour envoyer une requête de communication inter-origine à la page RP. Une fois l'utilisateur connecté, le fournisseur d'identité doit:

  • Envoyez l'en-tête Set-Login: logged-in ou appelez l'API navigator.login.setStatus("logged-in") pour informer le navigateur que l'utilisateur s'est connecté.
  • Appelez IdentityProvider.close() pour fermer la boîte de dialogue.
Un utilisateur se connecte à un RP après s'être connecté au fournisseur d'identité à l'aide de FedCM.

Informer le navigateur de l'état de connexion de l'utilisateur

L'API Login Status est un mécanisme par lequel un site Web, en particulier un fournisseur d'identité, informe le navigateur de l'état de connexion de l'utilisateur sur le fournisseur d'identité. Avec cette API, le navigateur peut réduire les requêtes inutiles à l'IDP et atténuer les attaques par cassage de chiffrement potentielles.

Les fournisseurs d'identité peuvent signaler l'état de connexion de l'utilisateur au navigateur en envoyant un en-tête HTTP ou en appelant une API JavaScript lorsque l'utilisateur est connecté au fournisseur d'identité ou lorsqu'il est déconnecté de tous ses comptes de fournisseur d'identité. Pour chaque IdP (identifié par son URL de configuration), le navigateur conserve une variable à trois états représentant l'état de connexion avec les valeurs possibles suivantes:

  • logged-in
  • logged-out
  • unknown (par défaut)
État de connexion Description
logged-in Lorsque l'état de connexion de l'utilisateur est défini sur logged-in, le RP appelant FedCM envoie des requêtes au point de terminaison des comptes de l'IDP et affiche les comptes disponibles à l'utilisateur dans la boîte de dialogue FedCM.
logged-out Lorsque l'état de connexion de l'utilisateur est logged-out, l'appel du FedCM échoue de manière silencieuse sans envoyer de requête au point de terminaison des comptes de l'IDP.
unknown (par défaut) L'état unknown est défini avant que l'IDP n'envoie un signal à l'aide de l'API Login Status. Lorsque l'état est unknown, le navigateur envoie une requête au point de terminaison de comptes de l'IDP et met à jour l'état en fonction de la réponse du point de terminaison de comptes.

Pour indiquer que l'utilisateur est connecté, envoyez un en-tête HTTP Set-Login: logged-in dans une navigation de premier niveau ou une requête de sous-ressource du même site à l'origine de l'IDP:

  Set-Login: logged-in

Vous pouvez également appeler la méthode JavaScript navigator.login.setStatus('logged-in') à partir de l'origine de l'IDP dans une navigation de niveau supérieur:

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

L'état de connexion de l'utilisateur sera défini sur logged-in.

Pour signaler que l'utilisateur est déconnecté de tous ses comptes, envoyez un en-tête HTTP Set-Login: logged-out dans une navigation de niveau supérieur ou une requête de sous-ressource du même site à l'origine de l'IDP:

  Set-Login: logged-out

Vous pouvez également appeler l'API JavaScript navigator.login.setStatus('logged-out') à partir de l'origine de l'IDP dans une navigation de premier niveau:

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

L'état de connexion de l'utilisateur sera défini sur logged-out.

L'état unknown est défini avant que l'IDP n'envoie un signal à l'aide de l'API Login Status. Le navigateur envoie une requête au point de terminaison des comptes de l'IDP et met à jour l'état en fonction de la réponse du point de terminaison des comptes:

  • Si le point de terminaison renvoie une liste de comptes actifs, définissez l'état sur logged-in et ouvrez la boîte de dialogue FedCM pour afficher ces comptes.
  • Si le point de terminaison ne renvoie aucun compte, définissez l'état sur logged-out et échouez l'appel FedCM.

Autoriser l'utilisateur à se connecter via un flux de connexion dynamique

Même si l'IDP continue d'informer le navigateur de l'état de connexion de l'utilisateur, il peut être désynchronisé, par exemple lorsque la session expire. Le navigateur tente d'envoyer une requête authentifiée au point de terminaison des comptes lorsque l'état de connexion est logged-in, mais le serveur ne renvoie aucun compte, car la session n'est plus disponible. Dans ce cas, le navigateur peut permettre à l'utilisateur de se connecter dynamiquement à l'IDP via une fenêtre pop-up.

Étapes suivantes

Implémentez FedCM pour vos RP et distribuez le SDK JavaScript. Mettez à jour vos RP en vous libérant de l'auto-implémentation.
Découvrez comment configurer votre environnement et déboguer votre implémentation.