Обновления FedCM: пробные версии Origin для пакета Continuation API и автоматическое предоставление Storage Access API.

Начиная с Chrome 126 разработчики могут запустить пробную версию origin для пакета функций API Federated Credential Management (FedCM) для настольных компьютеров, которые позволяют использовать некоторые сценарии авторизации . Пакет состоит из API Continuation и API Parameters, которые позволяют использовать поток авторизации OAuth, включающий диалоговое окно разрешений, предоставляемое поставщиком удостоверений (IdP). Пакет также включает другие изменения, такие как API Fields, Multiple configURL и Custom Account Labels. Начиная с Chrome 126 мы также представляем пробную версию origin для API Storage Access (SAA), который автоматически предоставляет запросы SAA, если пользователь успешно вошел в систему с помощью FedCM в прошлом.

Пробная версия Origin: пакет API FedCM Continuation

Пакет API FedCM Continuation состоит из нескольких расширений FedCM:

Продолжение API

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

Вы можете ознакомиться с демоверсией API на Glitch .

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

Обычно конечная точка подтверждения идентификатора возвращает токен, необходимый для аутентификации.

{
  "token": "***********"
}

Однако с помощью Continuation API конечная точка утверждения идентификатора может возвращать свойство 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 pop-up window:
  "continue_on": "/oauth/authorize?scope=..."
}

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

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

document.getElementById('allow_btn').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.close() .

IdentityProvider.close();

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

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

Параметры API

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

Чтобы использовать API, добавьте параметры в свойство params как объект в вызове navigator.credentials.get() .

let {token} = await navigator.credentials.get({
  identity: {
    providers: [{
      clientId: '1234',
      configURL: 'https://idp.example/fedcm.json',
      // Key/value pairs that need to be passed from the
      // RP to the IdP but that don't really play any role with
      // the browser.
      params: {
        IDP_SPECIFIC_PARAM: '1',
        foo: 'BAR',
        ETC: 'MOAR',
        scope: 'calendar.readonly photos.write',
      }
    }],
  }
});

Имена свойств в объекте params начинаются с param_ . В приведенном выше примере свойство params содержит IDP_SPECIFIC_PARAM как '1' , foo как 'BAR' , ETC как 'MOAR' и scope как 'calendar.readonly photos.write' . Это будет переведено как param_IDP_SPECIFIC_PARAM=1&param_foo=BAR&param_ETC=MOAR&param_scope=calendar.readonly%20photos.write в теле HTTP-запроса:

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

account_id=123&client_id=client1234&nonce=234234&disclosure_text_shown=false&param_IDP_SPECIFIC_PARAM=1&param_foo=BAR&param_ETC=MOAR&param_scope=calendar.readonly%20photos.write

Получайте разрешения динамически

В целом, для пользователей наиболее полезно запрашивать разрешения, когда они необходимы, а не когда разработчик считает, что их проще всего реализовать. Например, запрос разрешения на доступ к камере, когда пользователь собирается сделать фотографию, предпочтительнее, чем запрос разрешения сразу, как только пользователь заходит на сайт. Та же практика применима к ресурсам сервера. Запрашивайте разрешения только тогда, когда они необходимы пользователю. Это называется «динамическая авторизация».

Чтобы динамически запросить авторизацию с помощью FedCM, IdP может:

  1. Вызовите navigator.credentials.get() с требуемыми параметрами, которые может понять IdP, например, scope .
  2. Конечная точка подтверждения идентификатора подтверждает, что пользователь уже вошел в систему, и отвечает URL-адресом continue_on .
  3. Браузер открывает всплывающее окно со страницей разрешений IdP, запрашивающее дополнительное разрешение, соответствующее запрошенным областям.
  4. После авторизации IdP с помощью IdentityProvider.resolve() окно закрывается, а исходный вызов navigator.credentials.get() RP получает соответствующий токен или код авторизации, чтобы RP мог обменять его на надлежащий токен доступа.

API полей

API полей позволяет RP объявлять атрибуты учетной записи для запроса от IdP, чтобы браузер мог отобразить надлежащий пользовательский интерфейс раскрытия в диалоге FedCM; IdP несет ответственность за включение запрошенных полей в возвращаемый токен. Рассмотрите это как запрос «базового профиля» в OpenID Connect по сравнению с «областями» в OAuth.

Сообщение о раскрытии информации в режиме виджета.
Сообщение о раскрытии информации в режиме виджета.
Раскрытие сообщения в кнопочном режиме.
Раскрытие сообщения в кнопочном режиме.

Чтобы использовать Fields API, добавьте параметры в свойство fields как массив в вызове navigator.credentials.get() . Поля могут содержать 'name' , 'email' и 'picture' на данный момент, но могут быть расширены для включения большего количества значений в будущем.

Запрос с fields будет выглядеть так:

let { token } = await navigator.credentials.get({
  identity: {
    providers: [{
      fields: ['name', 'email', 'picture'],
      clientId: '1234',
      configURL: 'https://idp.example/fedcm.json',
      params: {
        scope: 'drive.readonly calendar.readonly',
      }
    }],
  }
  mediation: 'optional',
});

HTTP-запрос к конечной точке утверждения идентификатора включает параметр fields , указанных RP, при этом disclosure_text_shown присваивается значение true если это не вернувшийся пользователь, а также поля, которые браузер раскрыл пользователю в disclosure_shown_for :

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

account_id=123&client_id=client1234&nonce=234234&disclosure_text_shown=true&fields=email,name,picture&disclosure_shown_for=email,name,picture

Если RP требуется доступ к любым дополнительным данным от IdP, например, доступ к календарю, это должно быть обработано с помощью пользовательского параметра, как указано выше. IdP возвращает URL continue_on для запроса разрешения.

Если fields — пустой массив, запрос будет выглядеть так:

let { token } = await navigator.credentials.get({
  identity: {
    providers: [{
      fields: [],
      clientId: '1234',
      configURL: 'https://idp.example/fedcm.json',
      params: {
        scope: 'drive.readonly calendar.readonly',
      }
    }],
  }
  mediation: 'optional',
});

Если fields представляют собой пустой массив, пользовательский агент пропустит пользовательский интерфейс раскрытия.

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

Это происходит даже в том случае, если ответ от конечной точки учетных записей не содержит идентификатор клиента, соответствующий RP в approved_clients .

В этом случае сообщение disclosure_text_shown , отправленное в конечную точку утверждения идентификатора, имеет значение false в теле HTTP:

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

account_id=123&client_id=client1234&nonce=234234&disclosure_text_shown=false

Несколько configURL-адресов

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

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

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

{
  "provider_urls": [ "https://idp.example/fedcm.json" ],
  "accounts_endpoint": "https://idp.example/accounts",
  "login_url": "https://idp.example/login"
}

Это позволяет нам:

  1. Поддерживать прямую и обратную совместимость с существующими известными файлами и более ранними версиями браузеров, которые уже развернуты.
  2. Имейте произвольное количество файлов конфигурации — при условии, что все они указывают на одни и те же accounts_endpoint и login_url .
  3. Не имеет возможности добавлять энтропию к запросу на выборку учетных данных, сделанному в accounts_endpoint , поскольку она должна быть указана на уровне «.well-known».

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

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

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

Пример

IdP поддерживает два configURL для consumer и enterprise соответственно. Файл конфигурации consumer имеет метку 'consumer' , а файл конфигурации enterprise имеет метку 'enterprise' .

При такой настройке известный файл включает в себя accounts_endpoint и login_url , что позволяет использовать несколько configURL.

{
  "provider_urls": [ "https://idp.example/fedcm.json" ],
  "accounts_endpoint": "https://idp.example/accounts",
  "login_url": "https://idp.example/login"
}

Когда accounts_endpoint указан в хорошо известном файле, provider_urls игнорируются. RP может напрямую указывать на соответствующие файлы конфигурации в вызове navigator.credentials.get() .

Файл конфигурации потребителя находится по адресу https://idp.example/fedcm.json и включает свойство accounts , которое определяет 'consumer' с помощью include .

{
  "accounts_endpoint": "https://idp.example/accounts",
  "client_metadata_endpoint": "/client_metadata",
  "login_url": "https://idp.example/login",
  "id_assertion_endpoint": "/assertion",
  "accounts": {
    "include": "consumer"
  }
}

Файл конфигурации предприятия находится по адресу https://idp.example/enterprise/fedcm.json и включает свойство accounts , которое указывает 'enterprise' с помощью include .

{
  "accounts_endpoint": "https://idp.example/accounts",
  "client_metadata_endpoint": "/enterprise/client_metadata",
  "login_url": "https://idp.example/login",
  "id_assertion_endpoint": "/assertion",
  "accounts": {
    "include": "enterprise"
  }
}

Общая конечная точка учетных записей IdP (в этом примере https://idp.example/accounts ) возвращает список учетных записей, который включает свойство labels с назначенными labels в массиве для каждой учетной записи. Ниже приведен пример ответа для пользователя, у которого есть две учетные записи. Одна для потребителя, а другая для предприятия:

{
 "accounts": [{
   "id": "123",
   "given_name": "John",
   "name": "John Doe",
   "email": "john_doe@idp.example",
   "picture": "https://idp.example/profile/123",
   "labels": ["consumer"]
  }], [{
   "id": "4567",
   "given_name": "Jane",
   "name": "Jane Doe",
   "email": "jane_doe@idp.example",
   "picture": "https://idp.example/profile/4567",
   "labels": ["enterprise"]
  }]
}

Если RP хочет разрешить пользователям 'enterprise' входить в систему, он может указать URL-адрес конфигурации 'enterprise' 'https://idp.example/enterprise/fedcm.json' в вызове navigator.credentials.get() :

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

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

Пробный запуск Origin: FedCM как сигнал доверия для API доступа к хранилищу

Chrome 126 запускает исходный пробный период FedCM как сигнала доверия для API доступа к хранилищу . С этим изменением предварительное предоставление разрешения через FedCM становится веской причиной для автоматического одобрения запроса на доступ к хранилищу API доступа к хранилищу .

Это полезно, когда встроенный iframe хочет получить доступ к персонализированным ресурсам: например, если idp.example встроен в rp.example и должен показать персонализированный ресурс. Если браузер ограничивает доступ к сторонним файлам cookie, даже если пользователь вошел в rp.example с помощью idp.example с FedCM, встроенный iframe idp.example не сможет запрашивать персонализированные ресурсы, поскольку запросы не будут включать сторонние файлы cookie.

Для этого idp.example необходимо получить разрешение на доступ к хранилищу через встроенный в веб-сайт iframe, а получить его можно только с помощью запроса разрешения.

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

// In top-level rp.example:

// Ensure FedCM permission has been granted.
const cred = await navigator.credentials.get({
  identity: {
    providers: [{
      configURL: 'https://idp.example/fedcm.json',
      clientId: '123',
    }],
  },
  mediation: 'optional',
});

// In an embedded IdP iframe:

// No user gesture is needed to call this, and the call will be auto-granted.
await document.requestStorageAccess();

// This returns `true`.
const hasAccess = await document.hasStorageAccess();

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

Примите участие в исследовании происхождения

Вы можете попробовать пакет API FedCM Continuation локально, включив флаг Chrome chrome://flags#fedcm-authz в Chrome 126 или более поздней версии. Вы также можете попробовать FedCM в качестве сигнала доверия для API Storage Access локально, включив #fedcm-with-storage-access-api в Chrome 126 или более поздней версии.

Эти функции также доступны в виде пробных версий Origin. Пробные версии Origin позволяют вам попробовать новые функции и дать отзыв об их удобстве использования, практичности и эффективности. Для получения дополнительной информации ознакомьтесь с разделом Начало работы с пробными версиями Origin .

Чтобы попробовать пробную версию API-пакета FedCM Continuation , создайте два пробных токена Origin:

Если вы заинтересованы во включении Continuation API вместе с потоком кнопок , включите также пробную версию API Button Mode :

Чтобы попробовать FedCM в качестве сигнала доверия для пробной версии API доступа к хранилищу :

Пробная версия Continuation API Bundle и FedCM как сигнал доверия для пробной версии Storage Access API доступны с Chrome 126.

Зарегистрируйте пробную версию стороннего источника для RP

  1. Перейдите на страницу регистрации пробной версии Origin.
  2. Нажмите кнопку «Зарегистрироваться» и заполните форму для запроса токена.
  3. Введите источник IdP как Web Origin .
  4. Установите флажок «Стороннее сопоставление», чтобы внедрить токен с помощью JavaScript в другие источники.
  5. Нажмите «Отправить» .
  6. Встроить выпущенный токен на сторонний сайт.

Чтобы встроить токен на сторонний веб-сайт, добавьте следующий код в библиотеку JavaScript IdP или SDK, предоставляемый из источника IdP.

const tokenElement = document.createElement('meta');
tokenElement.httpEquiv = 'origin-trial';
tokenElement.content = 'TOKEN_GOES_HERE';
document.head.appendChild(tokenElement);

Замените TOKEN_GOES_HERE на свой собственный токен.