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

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

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

  1. Создайте общеизвестный файл .
  2. Создайте конфигурационный файл .
  3. Создайте следующие конечные точки:
  4. Сообщите браузеру о статусе входа пользователя в систему .

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

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

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

Свойство Необходимый Описание
accounts_endpoint Требуется, если файл конфигурации содержит конечную точку client_metadata . URL-адрес конечной точки учетных записей. Это позволяет поддерживать несколько конфигураций, при условии, что в каждом конфигурационном файле используются одни и те же URL-адреса login_url и accounts_endpoint .

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

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

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

  {
     // You must include accounts_endpoint and login_url if your
     // config file specifies a client_metadata_endpoint
    "accounts_endpoint": "https://accounts.idp.example/accounts",
    "login_url": "https://accounts.idp.example/login"
  }

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

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

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

Конфигурационный файл поставщика идентификации (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

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

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

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

Примечание: поддержка пользовательских меток учетных записей доступна начиная с Chrome 132.
supports_use_other_account (необязательно) Логическое значение, указывающее, может ли пользователь войти в систему с учетной записью, отличной от той, с которой он авторизован (если поставщик идентификации поддерживает несколько учетных записей). Это относится только к активному режиму.
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

Используйте другой аккаунт

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

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

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

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

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

Браузер отправляет GET запрос с куки, имеющими SameSite=None , но без параметра client_id , заголовка Origin или заголовка Referer . Это фактически препятствует поставщику идентификации (IdP) узнать, к какому поставщику услуг (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 (необязательно) Массив строковых пользовательских меток учетных записей, с которыми связана данная учетная запись.
Поставщик идентификационных данных может реализовать пользовательскую маркировку учетных записей следующим образом:
  • Укажите метки учетных записей в конечной точке accounts (используя параметр label_hints ).
  • Создайте конфигурационный файл для каждой конкретной метки.

Например, поставщик идентификации (IdP) реализует конфигурационный файл https://idp.example/developer-config.json с указанным параметром "account_label": "developer" . IdP также помечает некоторые учетные записи меткой "developer" используя параметр label_hints в конечной точке accounts . Когда поставщик услуг (RP) вызывает 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.

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

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

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

    Примечание: Начиная с Chrome 141, текст раскрытия может отображаться, даже если значение параметра disclosure_text_shown равно "false" . Чтобы проверить, был ли отображен текст раскрытия, проверьте вместо этого значение параметра disclosure_shown_for .
disclosure_shown_for Перечисляет поля, которые браузер показал пользователю в тексте уведомления, чтобы сообщить ему, какие данные запрашивает поставщик идентификации (IdP) принимающая сторона (RP).
is_auto_selected Если на стороне RP выполняется автоматическая повторная аутентификация , is_auto_selected указывает на "true" . В противном случае - на "false" . Это полезно для поддержки дополнительных функций, связанных с безопасностью. Например, некоторые пользователи могут предпочитать более высокий уровень безопасности, требующий явного участия пользователя в аутентификации. Если поставщик идентификации получает запрос на токен без такого участия, он может обработать запрос по-другому. Например, вернуть код ошибки, чтобы 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 с ID уже авторизованной учетной записи. Отклоните запрос, если идентификаторы не совпадают.
  5. Отправьте токен. Если запрос отклонен, отправьте сообщение об ошибке .

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

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

Свойство Описание
token Токен — это строка или объект any типа, содержащий утверждения об аутентификации.

Примечание: поддержка типа «Объект» доступна начиная с Chrome версии 143.
continue_on URL-адрес перенаправления, обеспечивающий многоэтапный процесс авторизации.

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

{
  // IdP can respond with a token object to authenticate the user
  "token": {
    "access_token": "a1b2c3d4e5f6...",
    "user_info": {
      "email": "jane.doe@company.example",
      "given_name": "Jane",
      "family_name": "Doe"
    }
  }
}

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

Поставщик идентификации (IdP) может указать 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 dialog 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() .
Если пользователь отклоняет запрос, поставщик идентификации может закрыть окно, вызвав метод IdentityProvider.close() .

  IdentityProvider.close();

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

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

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

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

Возвращает сообщение об ошибке.

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

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

Пользовательские метки учетных записей

С помощью пользовательских меток учетных записей поставщик идентификации (IdP) может добавлять метки к учетным записям пользователей, а поставщик услуг (RP) может выбирать, какие учетные записи получать, только с определенными метками, указывая configURL для этой конкретной метки. Это может быть полезно, когда поставщику услуг необходимо отфильтровать учетные записи по определенным критериям, например, чтобы отображать только учетные записи, относящиеся к определенным ролям, таким как "developer" или "hr" .

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

Рассмотрим поставщика идентификации (IdP), который хочет различать учетные записи "developer" и "hr" . Для этого IdP должен поддерживать два 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 accounts (в этом примере 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',
        configURL: 'https://idp.example/hr/fedcm.json',
        params: {
            nonce: '234234'
        }
      },
    }
  });

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

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

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

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

Вызывая IdentityCredential.disconnect() , браузер отправляет междоменный POST запрос с файлами cookie, содержащими SameSite=None и content-type 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), передайте строку, которая не соответствует ни одному идентификатору учетной записи, например "*" .

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

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

Браузер отправляет GET запрос, используя client_id navigator.credentials.get без cookie. Если API FedCM вызывается с межсайтового источника, также отправляется параметр top_frame_origin . Например:

  GET /client_metadata.example?client_id=1234&top_frame_origin=https%3A%2F%2Ftop-frame.example HTTP/1.1
  Host: accounts.idp.example
  Origin: https://rp.example/
  Accept: application/json
  Sec-Fetch-Dest: webidentity

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

  1. Определите RP для client_id .
  2. [Необязательно] Если в запросе указан параметр top_frame_origin , проверьте, являются ли RP и верхний фрейм одной и той же стороной, чтобы решить, следует ли браузеру вызывать домен iframe. Поставщики идентификации должны определить свою собственную логику для этого.
  3. Предоставьте клиенту метаданные в ответном сообщении.

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

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

Браузер ожидает от конечной точки ответ в формате 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-файлы. Все, что происходит внутри диалогового окна, зависит от поставщика идентификации (IdP), и отсутствуют дескрипторы окон для отправки запроса на междоменную связь со страницей поставщика идентификации (RP). После авторизации пользователя поставщик идентификации должен:

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

Сообщите браузеру о статусе входа пользователя в систему.

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

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

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

Чтобы подтвердить авторизацию пользователя, отправьте 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 устанавливается до того, как поставщик идентификации (IdP) отправит сигнал с помощью API статуса входа в систему. Браузер отправляет запрос к конечной точке учетных записей IdP и обновляет статус на основе ответа от конечной точки учетных записей:

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

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

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