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

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

Для внедрения FedCM поставщики удостоверений должны выполнить следующие шаги:

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

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

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

Свойство Необходимый Описание
provider_urls необходимый Массив путей к файлам конфигурации IdP. Игнорируется (но все равно требуется), если указаны accounts_endpoint и login_url .
accounts_endpoint рекомендуется, требуется login_url
URL-адрес конечной точки учетной записи. Это позволяет поддерживать несколько конфигураций, при условии, что каждый файл конфигурации использует один и тот же URL-адрес login_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"]
  }

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

  • 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 и конечные точки.

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

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

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

RP передаст URL-адрес файла конфигурации вызову API FedCM, чтобы пользователь мог войти в систему:

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

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

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

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

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

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

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

Примечание. Функция «Использовать другую учетную запись» и активный режим поддерживаются в Chrome 132.
modes.passive

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

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

Конечные точки поставщика удостоверений
Конечные точки поставщика удостоверений

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

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

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

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

Конечная точка аккаунтов

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

Браузер отправляет запрос GET с файлами cookie с 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 (обязательно) Имя и фамилия пользователя.
email (обязательно) Адрес электронной почты пользователя.
given_name (необязательно) Имя пользователя.
picture (необязательно) URL-адрес изображения аватара пользователя.
approved_clients (необязательно) Массив идентификаторов клиентов RP, под которыми зарегистрировался пользователь.
login_hints (необязательно) Массив всех возможных типов фильтров, которые поддерживает IdP для указания учетной записи. RP может вызвать navigator.credentials.get() со свойством loginHint для выборочного отображения указанной учетной записи.
domain_hints (необязательно) Массив всех доменов, с которыми связана учетная запись. RP может вызвать navigator.credentials.get() со свойством domainHint для фильтрации учетных записей.
labels (по желанию) Массив строковых меток пользовательских учетных записей, с которыми связана учетная запись.
Поставщик удостоверений может реализовать специальную маркировку учетных записей следующим образом:
  • Укажите метки учетных записей в конечной точке учетных записей (используя этот параметр labels ).
  • Создайте файл конфигурации для каждой конкретной метки.

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

Если пользователь не вошел в систему, ответьте 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 не включает одно или несколько из трех полей («имя», «электронная почта» и «изображение»), например, fields=[ ] или fields=['name', 'picture'] . Это необходимо для обратной совместимости со старыми реализациями IdP, которые ожидают, что строка раскрытия всегда будет включать все три поля.
is_auto_selected Если на RP выполняется автоматическая повторная аутентификация , is_auto_selected указывает "true" . В противном случае "false" . Это полезно для поддержки большего количества функций, связанных с безопасностью. Например, некоторые пользователи могут предпочесть более высокий уровень безопасности, который требует явного посредничества пользователя при аутентификации. Если IdP получает запрос токена без такого посредничества, он может обработать запрос по-другому. Например, верните код ошибки, чтобы RP мог снова вызвать API FedCM с помощью mediation: required .
fields (необязательно) Массив строк, определяющий информацию о пользователе («имя», «адрес электронной почты», «изображение»), которой RP должен поделиться с IdP.
Браузер отправит fields disclosure_text_shown и disclosure_shown_for перечисления указанных полей в запросе POST, как в следующем примере .

Примечание. Параметр Fields поддерживается начиная с Chrome 132.
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&disclosure_text_shown=true&fields=email,picture&disclosure_shown_for=email,picture

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

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

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

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

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

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

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

Продолжить работу над функцией

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

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

Конечная точка утверждения идентификатора может возвращать свойство 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. Одноразовый вызов IdentityProvider.resolve() — единственный способ взаимодействия родительского окна (RP) и всплывающего окна (IdP).
Если пользователь отклоняет запрос, IdP может закрыть окно, вызвав IdentityProvider.close() .

  IdentityProvider.close();

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

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

Если по какой-то причине пользователь изменил свою учетную запись во всплывающем окне (например, 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 отображает пользовательский интерфейс ошибки с общим сообщением об ошибке и передает код RP.
  • url : идентифицирует удобную для чтения веб-страницу с информацией об ошибке, чтобы предоставить пользователям дополнительную информацию об ошибке. Это поле полезно для пользователей, поскольку браузеры не могут отображать подробные сообщения об ошибках во встроенном пользовательском интерфейсе. Например: ссылки для следующих шагов или контактная информация службы поддержки клиентов. Если пользователь хочет узнать больше о деталях ошибки и о том, как ее исправить, он может посетить предоставленную страницу из пользовательского интерфейса браузера для получения более подробной информации. URL-адрес должен относиться к тому же сайту, что и configURL IdP.
  // id_assertion_endpoint response
  {
    "error" : {
      "code": "access_denied",
      "url" : "https://idp.example/error?type=access_denied"
    }
  }

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

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

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

Рассмотрим поставщика удостоверений, который хочет различать учетные записи "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",
    "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"
    }
  }
  • При такой настройке известный файл должен включать 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 ) возвращает список учетных записей, который включает свойство labels с назначенными метками в массиве для каждой учетной записи:
  {
  "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"]
    }]
  }

Если 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 на этом сайте.

  • Метки представляют собой строки. Если массив labels или поле include содержит что-то, не являющееся строкой, оно игнорируется.
  • Если в configURL не указаны метки, все учетные записи будут отображаться в средстве выбора учетной записи FedCM.
  • Если для учетной записи не указаны метки, она будет отображаться в средстве выбора учетной записи только в том случае, если configURL также не указана метка.
  • Если ни одна учетная запись не соответствует запрошенной метке в пассивном режиме (аналогично функции подсказки домена), в диалоговом окне 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 (совместное использование ресурсов между источниками) .
  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. Например:

  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-адрес страницы входа, указанный в файле конфигурации idp login_url .

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

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

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

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

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

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

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

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

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

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

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

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

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

unknown статус устанавливается до того, как поставщик удостоверений отправит сигнал с помощью API статуса входа. Браузер отправляет запрос к конечной точке учетных записей IdP и обновляет статус на основе ответа от конечной точки учетных записей:

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

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

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

Next steps

Implement FedCM for your RPs and distribute the JavaScript SDK. Keep RPs up-to-date by eliminating the need for self-implementation.
Learn how to setup your enviromnemt and debug your implementation.
,

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

Для внедрения FedCM поставщики удостоверений должны выполнить следующие шаги:

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

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

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

Свойство Необходимый Описание
provider_urls необходимый Массив путей к файлам конфигурации IdP. Игнорируется (но все равно требуется), если указаны accounts_endpoint и login_url .
accounts_endpoint рекомендуется, требуется login_url
URL-адрес конечной точки учетной записи. Это позволяет поддерживать несколько конфигураций, при условии, что каждый файл конфигурации использует один и тот же URL-адрес login_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"]
  }

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

  • 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 и конечные точки

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

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

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

RP передаст URL -адрес файла конфигурации в вызов API FEDCM, чтобы позволить пользователю войти в систему:

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

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

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

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

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

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

ПРИМЕЧАНИЕ. Пользовательские метки учетной записи поддерживаются из Chrome 132.
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 (необязательно) Массив объектов иконы. Эти значки отображаются в диалоговом окне входа. Объект Icon имеет два параметра:
  • url (требуется): URL изображения значка. Это не поддерживает изображения SVG.
  • size (необязательно): размеры значков, предполагаемые применением, чтобы быть квадратным и отдельным разрешением. Это число должно быть больше или равным 25px в пассивном режиме и больше или равное 40px в активном режиме.
modes Объект, который содержит спецификации того, как будет отображаться пользовательский интерфейс FedCM в разных режимах:
  • active
  • passive
modes.active Объект, содержащий свойства, которые позволяют настраивать поведение FedCM в определенном режиме. Оба modes.active modes.passive
  • supports_use_other_account : Boolean указывает, может ли пользователь войти в систему с учетной записью, отличной от той, с которой они в настоящее время вошли (если IDP поддерживает несколько учетных записей).

ПРИМЕЧАНИЕ. Используйте другую функцию учетной записи, а активный режим поддерживаются из Chrome 132.
modes.passive

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

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

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

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

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

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

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

Счетная конечная точка

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

Браузер отправляет запрос GET с помощью файлов cookie с 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. Убедитесь, что запрос содержит испытания Sec-Fetch-Dest: webidentity .
  2. Сопоставьте сеанс cookie с идентификаторами уже подписанных учетных записей.
  3. Ответьте списком учетных записей.

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

Свойство Описание
id (требуется) Уникальный идентификатор пользователя.
name (требуется) Дано и фамилия пользователя.
email (требуется) Адрес электронной почты пользователя.
given_name (необязательно) Дано имя пользователя.
picture (необязательно) URL -адрес пользовательского изображения аватара.
approved_clients (необязательно) Массив идентификаторов клиента RP, на которые зарегистрировал пользователь.
login_hints (необязательно) Массив всех возможных типов фильтра, которые поддерживает IDP для указания учетной записи. RP может вызвать navigator.credentials.get() с свойством loginHint , чтобы выборочно показать указанную учетную запись.
domain_hints (необязательно) Массив всех доменов, с которыми ассоциируется учетная запись. RP может вызвать navigator.credentials.get() с свойством domainHint для фильтрации учетных записей.
labels (необязательно) Массив строковых меток учетной записи, с которыми ассоциируется учетная запись.
IDP может реализовать пользовательскую маркировку учетной записи следующим образом:
  • Укажите метки учетной записи в конечной точке учетных записей (используя этот параметр labels ).
  • Создайте файл конфигурации для каждой конкретной метки.

Например, IDP реализует https://idp.example/developer-config.json файл конфигурации с "accounts": {"include": "developer"} . IDP также отмечает некоторые учетные записи с меткой "developer" с использованием параметра labels в конечной точке учетных записей . Когда 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.
      "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"]
    }]
  }

Если пользователь не подписан, ответьте 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 не включает в себя одно или несколько из трех полей («Имя», «Электронная почта» и «Картинка»), например, fields=[ ] или fields=['name', 'picture'] . Это необходимо для обратной совместимости с более старыми реализациями IDP, которые ожидают, что строка раскрытия всегда будет включать все три поля.
is_auto_selected Если на RP выполняется автоматическая реконструкция , is_auto_selected указывает "true" . В противном случае "false" . Это полезно для поддержки большего количества функций, связанных с безопасностью. Например, некоторые пользователи могут предпочесть более высокий уровень безопасности, который требует явного посредничества пользователей в аутентификации. Если IDP получает запрос токена без такого посредничества, они могут обрабатывать запрос по -разному. Например, верните код ошибки, чтобы RP мог снова вызвать API FedCM с помощью mediation: required .
fields (необязательно) Массив строк, которые указывают информацию пользователя («Имя», «Электронная почта», «Картинка»), который RP нуждается в IDP, чтобы поделиться с ними.
Браузер отправит fields , disclosure_text_shown и disclosure_shown_for в котором указаны указанные поля в запросе POST, как в следующем примере .

ПРИМЕЧАНИЕ. Параметр поля поддерживается из Chrome 132.
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&disclosure_text_shown=true&fields=email,picture&disclosure_shown_for=email,picture

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

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

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

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

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

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

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

Продолжить функцию

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

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

Конечная точка утверждения идентификатора может вернуть свойство 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 IDP должен вызвать 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. Однократный вызов IdentityProvider.resolve() -единственный способ для общения с родительским окном (RP) и всплывающего окна (IDP).
Если пользователь отклоняет запрос, IDP может закрыть окно, вызывая IdentityProvider.close() .

  IdentityProvider.close();

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

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

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

  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 должен быть одинакового сайта, что и IDP configURL .
  // id_assertion_endpoint response
  {
    "error" : {
      "code": "access_denied",
      "url" : "https://idp.example/error?type=access_denied"
    }
  }

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

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

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

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

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

Когда RP хочет позволить пользователям "hr" входить в систему, они могут указать конфигурацию https://idp.example/hr/fedcm.json в navigator.credentials.get() call:

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

В 123 , для пользователя доступен только идентификатор учетной записи 4567 .

  • Ярлыки - это струны. Если labels массивы или include поле, содержит что -то, что не является строкой, это игнорируется.
  • Если в configURL не указана метки, все учетные записи будут отображаться в выборе учетной записи FedCM.
  • Если для учетной записи не указано никаких метков, она будет отображаться только в выборе учетной записи, если configURL также не указана метка.
  • Если ни одна учетная запись не соответствует запрошенной метке в пассивном режиме (аналогично функции Hint Domain), в диалоговом окне 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 (совместное использование ресурсов по перекрестному происхождению) .
  2. Убедитесь, что запрос содержит испытания Sec-Fetch-Dest: webidentity .
  3. Сопоставьте заголовок Origin против RP Origin, определяемого client_id . Отвергай, если они не совпадают.
  4. Match account_hint против идентификаторов уже подписанных учетных записей.
  5. Отключите учетную запись пользователя от RP.
  6. Ответьте на браузер с идентифицированной информацией об учетной записи пользователя в формате JSON.

Пример ответа json полезной нагрузки выглядит так:

  {
    "account_id": "account456"
  }

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

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

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

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

Диалог FEDCM отображает сообщение, предлагающее знак, как показано на следующем изображении.

А
Диалог FEDCM, предлагающий войти в IDP.

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

Пример диалога FEDCM.
Пример диалога, показанного после нажатия в систему, в кнопку IDP.

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

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

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

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

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

  • logged-in
  • logged-out
  • unknown (по умолчанию)
Государство входа в систему Описание
logged-in Когда статус входа пользователя будет установлен для logged-in , RP Calling FedCM делает запросы на конечную точку учетных записей IDP и отображает доступные учетные записи пользователю в диалоговом окне FEDCM.
logged-out Когда статус входа пользователя logged-out , вызов FEDCM молча не выполняется, не выполняя запрос на конечную точку учетных записей IDP.
unknown (по умолчанию) unknown статус устанавливается до того, как IDP отправляет сигнал, используя API состояния входа в систему. Когда статус unknown , браузер делает запрос на конечную точку учетных записей IDP и обновляет статус на основе ответа с конечной точки учетных записей.

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

  Set-Login: logged-in

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

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

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

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

  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 через всплывающее окно .

Next steps

Implement FedCM for your RPs and distribute the JavaScript SDK. Keep RPs up-to-date by eliminating the need for self-implementation.
Learn how to setup your enviromnemt and debug your implementation.