Внедрение решения для идентификации с помощью FedCM на стороне поставщика удостоверений.

Реализация FedCM включает несколько основных этапов как для поставщика удостоверений (IdP) , так и для проверяющей стороны (RP) . Чтобы узнать, как реализовать FedCM на стороне проверяющей стороны , обратитесь к документации.

Для внедрения FedCM лицам, удостоверяющим личность, необходимо выполнить следующие шаги:

Создайте известный файл

Чтобы предотвратить злоупотребление API трекерами , необходимо предоставить известный файл из /.well-known/web-identity eTLD+1 поставщика удостоверений.

Известный файл может включать в себя следующие свойства:

Свойство Необходимый Описание
provider_urls необходимый Массив путей к файлам конфигурации IdP. Игнорируется (но всё ещё требуется), если указаны accounts_endpoint и login_url .
accounts_endpoint рекомендуется, требуется login_url
URL-адрес конечной точки учётных записей. Это обеспечивает поддержку нескольких конфигураций, при условии, что каждый файл конфигурации использует один и тот же login_url и URL-адрес accounts_endpoint .

Примечание: параметр поддерживается начиная с Chrome 132.
login_url рекомендуется, требуется accounts_endpoint URL-адрес страницы входа , по которому пользователь может войти в IdP. Это обеспечивает поддержку нескольких конфигураций, при условии, что каждый файл конфигурации использует одни и те же login_url и accounts_endpoint .

Примечание: параметр поддерживается начиная с Chrome 132.

Например, если конечные точки IdP обслуживаются по адресу https://accounts.idp.example/ , они должны обслуживать известный файл по https://idp.example/.well-known/web-identity , а также файл конфигурации IdP . Вот пример содержимого известного файла:

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

Поставщики удостоверений могут поддерживать несколько файлов конфигурации для одного поставщика удостоверений, указав accounts_endpoint и login_url в файле well-known. Эта функция может быть полезна в следующих случаях:

  • IdP должен поддерживать несколько различных тестовых и производственных конфигураций.
  • IdP должен поддерживать различные конфигурации для каждого региона (например, eu-idp.example и us-idp.example ).

Для поддержки нескольких конфигураций (например, для различия тестовой и производственной среды) IdP должен указать accounts_endpoint и 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"
  }

Создайте файл конфигурации IdP и конечные точки

Файл конфигурации поставщика удостоверений содержит список необходимых конечных точек для браузера. Поставщики удостоверений должны размещать один или несколько файлов конфигурации, а также необходимые конечные точки и URL-адреса. Все JSON-ответы должны иметь тип содержимого application/json .

URL-адрес файла конфигурации определяется значениями, предоставленными вызову navigator.credentials.get() выполняемому на RP . RP передаст URL-адрес файла конфигурации каждому поставщику удостоверений:

  // 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
  }

Браузер получит файл конфигурации с помощью GET -запроса без заголовков Origin и Referer . Запрос не содержит cookie-файлов и не перенаправляется. Это фактически не позволяет поставщику удостоверений узнать, кто отправил запрос и какая проверяющая сторона пытается подключиться. Например:

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

Поставщик удостоверений должен реализовать конечную точку конфигурации, которая отвечает JSON-файлом. JSON-файл включает следующие свойства:

Свойство Описание
accounts_endpoint (обязательно) URL для конечной точки аккаунта .
account_label (необязательно) Пользовательская строка метки учетной записи, определяющая, какие учетные записи должны возвращаться при использовании этого файла конфигурации, например: "account_label": "developer" .
Поставщик удостоверений может реализовать пользовательскую маркировку учетных записей следующим образом:

Например, поставщик удостоверений реализует файл конфигурации "https://idp.example/developer-config.json" с указанием "account_label": "developer" . Поставщик удостоверений также помечает некоторые учётные записи меткой "developer" с помощью параметра label_hints в конечной точке accounts . Когда поставщик удостоверений вызывает navigator.credentials.get() с указанием файла конфигурации "https://idp.example/developer-config.json" , будут возвращены только учётные записи с меткой "developer" .

Примечание: Пользовательские метки учетных записей поддерживаются, начиная с Chrome 132.
supports_use_other_account (необязательно) Логическое значение, определяющее, может ли пользователь войти в систему с учётной записью, отличной от той, с которой он в данный момент вошёл (если IdP поддерживает несколько учётных записей). Это применимо только к активному режиму.
client_metadata_endpoint (необязательно) URL для конечной точки метаданных клиента .
id_assertion_endpoint (обязательно) URL для конечной точки утверждения идентификатора .
disconnect (необязательно) URL для конечной точки отключения .
login_url (обязательно) URL-адрес страницы входа , на которой пользователь может войти в IdP.
branding (опционально) Объект, содержащий различные варианты брендинга.
branding.background_color (необязательно) Параметр брендинга, который задаёт цвет фона кнопки «Продолжить как...». Используйте соответствующий синтаксис CSS, а именно hex-color , hsl() , rgb() или named-color .
branding.color (необязательно) Параметр брендинга, который задаёт цвет текста кнопки «Продолжить как...». Используйте соответствующий синтаксис CSS, а именно hex-color , hsl() , rgb() или named-color .
branding.icons (необязательно) Массив объектов-значков. Эти значки отображаются в диалоговом окне входа. Объект-значок имеет два параметра:
  • url (обязательно): URL-адрес изображения значка. Изображения SVG не поддерживаются.
  • size (необязательно): Размеры значка, которые приложение считает квадратными и имеют одинаковое разрешение. Это значение должно быть больше или равно 25 пикселей в пассивном режиме и больше или равно 40 пикселей в активном режиме.

Вот пример текста ответа от 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
      }]
    }
  }

После того как браузер извлекает файл конфигурации, он отправляет последующие запросы конечным точкам IdP:

Конечные точки IdP
Конечные точки IdP

Использовать другую учетную запись

Пользователи могут переключиться на учетную запись, отличную от той, с которой они в данный момент вошли в систему, если IdP поддерживает несколько учетных записей или замену существующей учетной записи.

Чтобы пользователь мог выбирать другие учетные записи, IdP должен указать эту функцию в файле конфигурации :

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

Конечная точка учетных записей

Конечная точка учётных записей поставщика удостоверений (IdP) возвращает список учётных записей, в которые пользователь вошел на IdP. Если IdP поддерживает несколько учётных записей, эта конечная точка вернёт все вошедшие в систему учётные записи.

Браузер отправляет GET запрос с cookie-файлами SameSite=None , но без параметра client_id , заголовка Origin или заголовка Referer . Это фактически не позволяет поставщику удостоверений определить, в какую RP пользователь пытается войти. Например:

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

Получив запрос, сервер должен:

  1. Убедитесь, что запрос содержит HTTP-заголовок Sec-Fetch-Dest: webidentity .
  2. Сопоставьте сеансовые cookie-файлы с идентификаторами уже зарегистрированных учетных записей.
  3. Предоставьте список аккаунтов.

Браузер ожидает ответ JSON, включающий свойство accounts с массивом информации об учетных записях со следующими свойствами:

Свойство Описание
id (обязательно) Уникальный идентификатор пользователя.
name Полное имя пользователя в соответствии с его локалью и предпочтениями.

Примечание: Начиная с Chrome 141, требуется как минимум один из параметров: name , email , username или tel . В более ранних версиях Chrome требовались оба параметра: name и email .
username Имя пользователя, выбранное пользователем.

Примечание: Начиная с Chrome 141, требуется по крайней мере один из параметров: name , email , username или tel .
email Адрес электронной почты пользователя.

Примечание: Начиная с Chrome 141, требуется как минимум один из параметров: name , email , username или tel . В более ранних версиях Chrome требовались оба параметра: name и email .
tel Номер телефона пользователя.

Примечание: Начиная с Chrome 141, требуется по крайней мере один из параметров: name , email , username или tel .
picture (необязательно) URL-адрес изображения аватара пользователя.
given_name (необязательно) Имя пользователя.
approved_clients (необязательно) Массив идентификаторов клиентов RP, с которыми зарегистрировался пользователь.
login_hints (необязательно) Массив всех возможных типов фильтров, поддерживаемых IdP для указания учётной записи. RP может вызвать navigator.credentials.get() со свойством loginHint для выборочного отображения указанной учётной записи.
domain_hints (необязательно) Массив всех доменов, с которыми связана учётная запись. RP может вызвать navigator.credentials.get() со свойством domainHint для фильтрации учётных записей.
label_hints (необязательно) Массив строковых пользовательских меток учетных записей, с которыми связана учетная запись.
Поставщик удостоверений может реализовать пользовательскую маркировку учетных записей следующим образом:
  • Укажите метки учетных записей в конечной точке учетных записей (используя параметр label_hints ).
  • Создайте файл конфигурации для каждой конкретной метки.

Например, поставщик удостоверений реализует файл конфигурации https://idp.example/developer-config.json с указанием "account_label": "developer" . Поставщик удостоверений также помечает некоторые учётные записи меткой "developer" с помощью параметра label_hints в конечной точке accounts . Когда поставщик удостоверений вызывает navigator.credentials.get() с указанным файлом конфигурации https://idp.example/developer-config.json , будут возвращены только учётные записи с меткой "developer" .

Пользовательские метки учетных записей отличаются от подсказок для входа в систему и подсказок для домена тем, что они полностью поддерживаются сервером IdP, а RP указывает только файл конфигурации для использования.

Примечание: Пользовательские метки учетных записей поддерживаются, начиная с Chrome 132.

Пример текста ответа:

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

Если пользователь не вошел в систему, ответьте HTTP 401 (Неавторизованный).

Возвращенный список учетных записей используется браузером и не будет доступен RP.

Конечная точка утверждения идентификатора

Конечная точка подтверждения идентификатора поставщика удостоверений (IdP) возвращает подтверждение для вошедшего в систему пользователя. Когда пользователь входит на сайт поставщика удостоверений (RP) с помощью вызова navigator.credentials.get() , браузер отправляет POST запрос с файлами cookie, SameSite=None и типом контента application/x-www-form-urlencoded на эту конечную точку, содержащую следующую информацию:

Свойство Описание
client_id (обязательно) Идентификатор клиента RP.
account_id (обязательно) Уникальный идентификатор вошедшего в систему пользователя.
disclosure_text_shown Результатом будет строка "true" или "false" (а не логическое значение). Результатом будет "false" в следующих случаях:
  • Если текст раскрытия не был показан, поскольку идентификатор клиента RP был включен в список свойств approved_clients ответа от конечной точки учетных записей .
  • Если текст раскрытия не был показан, поскольку браузер наблюдал момент регистрации в прошлом при отсутствии approved_clients .
  • Если параметр fields не включает все три поля («имя», «email» и «изображение»), например, fields=[ ] или fields=['name', 'picture'] . Это необходимо для обратной совместимости со старыми реализациями.

    Примечание: Начиная с Chrome 141, текст раскрытия может отображаться, даже если значение параметра disclosure_text_shown равно "false" . Чтобы проверить, отображался ли текст раскрытия, проверьте значение disclosure_shown_for .
disclosure_shown_for Перечисляет поля, которые браузер показал пользователю в тексте раскрытия, чтобы уведомить пользователя, какие данные RP запрашивает у IdP.
is_auto_selected Если на RP выполняется автоматическая повторная аутентификация , is_auto_selected принимает значение "true" . В противном случае — "false" . Это полезно для поддержки дополнительных функций безопасности. Например, некоторые пользователи могут предпочесть более высокий уровень безопасности, требующий явного посредничества пользователя при аутентификации. Если IdP получает запрос токена без такого посредничества, он может обработать запрос иначе. Например, вернуть код ошибки, чтобы RP мог снова вызвать API FedCM с mediation: required .
fields (необязательно) Массив строк, содержащий информацию о пользователе, которую RP запросил у IdP. Можно указать следующие поля (опционально):
  • "name"
  • "username"
  • "email"
  • "tel"
  • "picture"
Браузер отправит fields , disclosure_text_shown и disclosure_shown_for перечислив указанные поля в запросе POST, как в следующем примере .

Примечание: API Fields поддерживается в Chrome 132 и более поздних версиях. Поля `"username"` и `"tel"` поддерживаются, начиная с Chrome 141.
params (необязательно) Любой допустимый объект JSON, позволяющий указывать дополнительные пользовательские параметры «ключ-значение», например:
  • scope : строковое значение, содержащее дополнительные разрешения, которые необходимо запросить RP, например "drive.readonly calendar.readonly"
  • nonce : случайная строка, предоставляемая RP для обеспечения выдачи ответа на данный запрос. Предотвращает атаки повторного воспроизведения.
  • Другие пользовательские параметры «ключ-значение».
Когда браузер отправляет запрос POST, значение params будет сериализовано в JSON, а затем закодировано в процентах .

Примечание: API параметров поддерживается Chrome 132 и более поздними версиями.

Пример 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

Получив запрос, сервер должен:

  1. Ответьте на запрос с помощью CORS (Cross-Origin Resource Sharing) .
  2. Убедитесь, что запрос содержит HTTP-заголовок Sec-Fetch-Dest: webidentity .
  3. Сопоставьте заголовок Origin с источником RP, определенным по client_id . Отклоните, если они не совпадают.
  4. Сопоставьте account_id с идентификатором уже вошедшей учётной записи. Отклоните, если они не совпадают.
  5. Ответьте токеном. Если запрос отклонён, отправьте сообщение об ошибке .

Поставщик удостоверений может самостоятельно решить, как выпустить токен. Как правило, он подписывается такой информацией, как идентификатор учётной записи, идентификатор клиента, происхождение эмитента и одноразовый код, чтобы проверяющий поставщик мог проверить подлинность токена.

Браузер ожидает ответ JSON, включающий следующее свойство:

Свойство Описание
token Токен — это строка, содержащая утверждения об аутентификации.
continue_on URL-адрес перенаправления, обеспечивающий многоэтапный процесс входа в систему.

Возвращенный токен передается браузером в RP, чтобы RP мог проверить аутентификацию.

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

Продолжить чтение

Поставщик удостоверений может предоставить URL-адрес перенаправления в ответе конечной точки подтверждения идентификатора , чтобы обеспечить многоэтапный процесс входа. Это полезно, когда поставщику удостоверений необходимо запросить дополнительную информацию или разрешения, например:

  • Разрешение на доступ к серверным ресурсам пользователя.
  • Проверка актуальности контактной информации.
  • Родительский контроль.

Конечная точка утверждения идентификатора может возвращать свойство continue_on , которое включает абсолютный или относительный путь к конечной точке утверждения идентификатора.

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

Если ответ содержит параметр continue_on , открывается новое всплывающее окно, которое перенаправляет пользователя по указанному пути. После взаимодействия пользователя со страницей continue_on поставщик удостоверений должен вызвать метод IdentityProvider.resolve() с токеном, переданным в качестве аргумента, чтобы можно было разрешить обещание из исходного вызова 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);
  });

Браузер автоматически закроет всплывающее окно и вернёт токен вызывающей стороне API. Единственный способ взаимодействия родительского окна (RP) и всплывающего окна (IdP) — однократный вызов IdentityProvider.resolve() .
Если пользователь отклоняет запрос, IdP может закрыть окно, вызвав IdentityProvider.close() .

  IdentityProvider.close();

Для работы Continuation API требуется явное взаимодействие с пользователем (щелчки). Вот как Continuation API работает с различными режимами медиации :

  • В passive режиме :
    • mediation: 'optional' (по умолчанию): API Continuation будет работать только с жестом пользователя, например, нажатием кнопки на странице или в пользовательском интерфейсе FedCM. При запуске автоматической повторной аутентификации без жеста пользователя всплывающее окно не открывается, а обещание отклоняется.
    • mediation: 'required' : всегда просит пользователя взаимодействовать, поэтому Continuation API всегда работает.
  • В активном режиме :
    • Активация пользователя требуется всегда. API Continuation всегда совместимо.

Если по какой-то причине пользователь изменил свою учетную запись во всплывающем окне (например, IdP предлагает функцию «использовать другую учетную запись» или в случаях делегирования), вызов разрешения принимает необязательный второй аргумент, позволяющий что-то вроде:

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

Вернуть ответ об ошибке

id_assertion_endpoint также может возвращать ответ «ошибка», который имеет два необязательных поля:

  • code : IdP может выбрать одну из известных ошибок из списка ошибок OAuth 2.0 ( invalid_request , unauthorized_client , access_denied , server_error и temporarily_unavailable ) или использовать любую произвольную строку. В последнем случае Chrome отображает пользовательский интерфейс ошибки с общим сообщением об ошибке и передает код проверяющей стороне.
  • url : идентифицирует удобочитаемую веб-страницу с информацией об ошибке, чтобы предоставить пользователям дополнительную информацию об ошибке. Это поле полезно для пользователей, поскольку браузеры не могут отображать подробные сообщения об ошибках во встроенном пользовательском интерфейсе. Например, ссылки для дальнейших действий или контактную информацию службы поддержки клиентов. Если пользователь хочет узнать больше об ошибке и о том, как её исправить, он может посетить указанную страницу в пользовательском интерфейсе браузера для получения дополнительных сведений. URL-адрес должен принадлежать тому же сайту, что и configURL поставщика удостоверений.
  // id_assertion_endpoint response
  {
    "error" : {
      "code": "access_denied",
      "url" : "https://idp.example/error?type=access_denied"
    }
  }

Пользовательские метки аккаунтов

С помощью Custom Account Labels поставщик удостоверений может аннотировать учётные записи пользователей метками, а проверяющая сторона может выбрать только учётные записи с определёнными метками, указав configURL для этой метки. Это может быть полезно, когда проверяющей стороне нужно отфильтровать учётные записи по определённым критериям, например, отображать только учётные записи, определённые для определённой роли, например, "developer" или "hr" .

Аналогичная фильтрация возможна с помощью функций Domain Hint и Login Hint , которые можно указать в вызове navigator.credentials.get() . Однако Custom Account Labels позволяет фильтровать пользователей, указывая файл конфигурации, что особенно полезно при использовании нескольких configURL . Custom Account Labels также отличается тем, что они предоставляются сервером IdP, а не RP, как подсказки для входа или домена.

Рассмотрим поставщика удостоверений, который хочет различать учётные записи "developer" и "hr" . Для этого поставщику удостоверений необходимо поддерживать два configURL для "developer" и "hr" соответственно:

  • Файл конфигурации разработчика https://idp.example/developer/fedcm.json имеет метку "developer" , а файл конфигурации предприятия https://idp.example/hr/fedcm.json имеет метку "hr" , как показано ниже:
  // 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"
  }
  • При такой настройке известный файл должен включать accounts_endpoint и login_url , чтобы разрешить использование нескольких configURL:
  {
    "provider_urls": [ "https://idp.example/fedcm.json" ],
    "accounts_endpoint": "https://idp.example/accounts",
    "login_url": "https://idp.example/login"
  }
  • Общая конечная точка учетных записей IdP (в этом примере https://idp.example/accounts ) возвращает список учетных записей, включающий свойство label_hints с назначенными метками в массиве для каждой учетной записи:
  {
  "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"]
    }]
  }

Если RP хочет разрешить пользователям "hr" входить в систему, он может указать configURL https://idp.example/hr/fedcm.json в вызове navigator.credentials.get() :

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

В результате пользователю для входа доступен только идентификатор учетной записи 4567 Идентификатор учетной записи 123 скрыт браузером, чтобы пользователю не была предоставлена ​​учетная запись, которая не поддерживается IdP на этом сайте.

Дополнительные соображения:

  • Метки — это строки. Если массив label_hints или поле account_label используют значение, не являющееся строкой, это значение игнорируется.
  • Если в configURL не указаны метки, все учетные записи будут отображены в средстве выбора учетных записей FedCM.
  • Если для учетной записи не указаны метки, эта учетная запись будет отображаться в средстве выбора учетных записей только в том случае, если configURL также не указана метка.
  • Если в пассивном режиме (аналогично функции Domain Hint) ни одна учётная запись не соответствует запрошенной метке, в диалоговом окне FedCM отображается запрос на вход в систему, позволяющий пользователю войти в учётную запись IdP. В активном режиме всплывающее окно входа открывается напрямую.

Отключить конечную точку

Вызывая IdentityCredential.disconnect() , браузер отправляет кросс-доменный запрос POST с файлами cookie с SameSite=None и типом содержимого application/x-www-form-urlencoded на эту конечную точку отключения со следующей информацией:

Свойство Описание
account_hint Подсказка для учетной записи IdP..
client_id Идентификатор клиента 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

Получив запрос, сервер должен:

  1. Ответьте на запрос с помощью CORS (Cross-Origin Resource Sharing) .
  2. Убедитесь, что запрос содержит HTTP-заголовок Sec-Fetch-Dest: webidentity .
  3. Сопоставьте заголовок Origin с источником RP, определенным по client_id . Отклоните, если они не совпадают.
  4. Сопоставьте account_hint с идентификаторами уже вошедших в систему учетных записей.
  5. Отключите учетную запись пользователя от RP.
  6. Ответьте браузеру, указав идентифицированную информацию об учетной записи пользователя в формате JSON.

Пример полезной нагрузки JSON ответа выглядит следующим образом:

  {
    "account_id": "account456"
  }

Вместо этого, если IdP хочет, чтобы браузер отключил все учетные записи, связанные с RP, передайте строку, которая не соответствует ни одному идентификатору учетной записи, например "*" .

Конечная точка метаданных клиента

Конечная точка метаданных клиента поставщика удостоверений возвращает метаданные проверяющей стороны, такие как политика конфиденциальности, условия обслуживания и значки логотипа поставщика удостоверений. Поставщики удостоверений должны заранее предоставить поставщику удостоверений ссылки на свою политику конфиденциальности и условия обслуживания. Эти ссылки отображаются в диалоговом окне входа, если пользователь ещё не зарегистрировался на поставщике удостоверений.

Браузер отправляет GET запрос, используя client_id navigator.credentials.get без cookie-файлов. Например:

  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

Получив запрос, сервер должен:

  1. Определите RP для client_id .
  2. Предоставьте ответ с метаданными клиента.

Свойства конечной точки метаданных клиента включают:

Свойство Описание
privacy_policy_url (необязательно) URL-адрес политики конфиденциальности RP.
terms_of_service_url (необязательно) URL-адрес условий обслуживания RP.
icons (необязательно) Массив объектов, например [{ "url": "https://rp.example/rp-icon.ico", "size": 40}]

Браузер ожидает JSON-ответ от конечной точки:

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

Возвращаемые клиентские метаданные используются браузером и не будут доступны RP.

URL-адрес для входа

Эта конечная точка используется для того, чтобы пользователь мог войти в IdP.

С помощью API статуса входа поставщик удостоверений (IdP) должен сообщать браузеру статус входа пользователя. Однако этот статус может быть несинхронизирован, например, по истечении сеанса . В таком случае браузер может динамически разрешить пользователю войти в IdP через URL-адрес страницы входа, указанный в login_url файла конфигурации IdP .

В диалоговом окне FedCM отобразится сообщение с предложением войти в систему, как показано на следующем рисунке.

Диалоговое окно FedCM с предложением войти в IdP.
Диалоговое окно FedCM с предложением войти в IdP.

Когда пользователь нажимает кнопку «Продолжить» , браузер открывает всплывающее окно для страницы входа в систему IdP.

Пример диалога FedCM.
Пример диалогового окна, отображаемого после нажатия кнопки входа в IdP.

Диалог представляет собой обычное окно браузера с собственными файлами cookie. Всё, что происходит в диалоге, зависит от поставщика удостоверений, и нет доступных дескрипторов окна для отправки запроса на кросс-доменную связь к странице поставщика удостоверений. После входа пользователя в систему поставщик удостоверений должен:

  • Отправьте заголовок Set-Login: logged-in или вызовите API navigator.login.setStatus("logged-in") чтобы сообщить браузеру, что пользователь вошел в систему.
  • Вызовите IdentityProvider.close() , чтобы закрыть диалог.
Пользователь входит в RP после входа в IdP с помощью FedCM.

Информировать браузер о статусе входа пользователя

API статуса входа — это механизм, с помощью которого веб-сайт, особенно поставщик удостоверений, сообщает браузеру статус входа пользователя на этом поставщике. С помощью этого API браузер может сократить количество ненужных запросов к поставщику удостоверений и предотвратить потенциальные атаки по времени .

Поставщики удостоверений могут сообщать браузеру о состоянии входа пользователя, отправляя HTTP-заголовок или вызывая JavaScript API, когда пользователь входит в систему поставщика удостоверений или выходит из всех своих учётных записей. Для каждого поставщика удостоверений (идентифицируемого по URL-адресу конфигурации) браузер хранит переменную с тремя состояниями, представляющую состояние входа, с возможными значениями:

  • logged-in
  • logged-out
  • unknown (по умолчанию)
Состояние входа Описание
logged-in Когда статус входа пользователя установлен на logged-in , RP, вызывающая FedCM, отправляет запросы к конечной точке учетных записей IdP и отображает доступные учетные записи для пользователя в диалоговом окне FedCM.
logged-out Если статус входа пользователя — logged-out , вызов FedCM автоматически завершается ошибкой без отправки запроса к конечной точке учетных записей IdP.
unknown (по умолчанию) Статус unknown устанавливается до того, как поставщик удостоверений отправляет сигнал через API статуса входа. Когда статус unknown , браузер отправляет запрос к конечной точке учётных записей поставщика удостоверений и обновляет статус на основе ответа от конечной точки учётных записей.

Чтобы сообщить, что пользователь вошел в систему, отправьте HTTP-заголовок Set-Login: logged-in в навигационном запросе верхнего уровня или в запросе подресурса того же сайта в источнике IdP:

  Set-Login: logged-in

В качестве альтернативы вызовите метод JavaScript navigator.login.setStatus('logged-in') из источника IdP в навигации верхнего уровня:

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

Статус входа пользователя будет установлен как logged-in .

Чтобы сообщить, что пользователь вышел из всех своих учетных записей, отправьте HTTP-заголовок Set-Login: logged-out в навигационном запросе верхнего уровня или в запросе подресурса того же сайта в источнике IdP:

  Set-Login: logged-out

В качестве альтернативы можно вызвать JavaScript API navigator.login.setStatus('logged-out') из источника IdP в навигации верхнего уровня:

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

Статус входа пользователя будет установлен как logged-out .

Статус unknown устанавливается до того, как поставщик удостоверений отправляет сигнал через API «Статус входа». Браузер отправляет запрос к конечной точке учётных записей поставщика удостоверений и обновляет статус на основе ответа от конечной точки учётных записей:

  • Если конечная точка возвращает список активных учетных записей, обновите статус на logged-in ​​и откройте диалоговое окно FedCM, чтобы отобразить эти учетные записи.
  • Если конечная точка не возвращает ни одной учетной записи, обновите статус на logged-out и отмените вызов FedCM.

Позвольте пользователю войти в систему через динамический процесс входа.

Несмотря на то, что поставщик удостоверений (IdP) постоянно сообщает браузеру статус входа пользователя, синхронизация может быть нарушена, например, по истечении сеанса. Браузер пытается отправить запрос на учётные данные к конечной точке учётных записей, когда статус входа — logged-in , но сервер не возвращает учётные записи, поскольку сеанс больше недоступен. В таком случае браузер может динамически разрешить пользователю войти в IdP через всплывающее окно .

Следующие шаги

Внедрите FedCM для своих RP и распространяйте JavaScript SDK. Поддерживайте актуальность RP, устраняя необходимость самостоятельной реализации.
Узнайте, как настроить среду и отладить реализацию.