Узнайте, как использовать FedCM для федерации удостоверений, сохраняющей конфиденциальность.
FedCM (федеративное управление учетными данными) — это сохраняющий конфиденциальность подход к федеративным службам идентификации (например, «Войти с помощью...»), при котором пользователи могут входить на сайты, не передавая свою личную информацию службе идентификации или сайту.
Чтобы узнать больше о вариантах использования FedCM, пользовательских потоках и дорожной карте API, ознакомьтесь с введением в FedCM API .
Среда разработки FedCM
Для использования FedCM вам необходим безопасный контекст (HTTPS или локальный хост) как на IdP, так и на RP в Chrome.
Код отладки в Chrome на Android
Настройте и запустите сервер локально для отладки кода FedCM. Вы можете получить доступ к этому серверу в Chrome на устройстве Android, подключенном с помощью USB-кабеля с переадресацией портов.
Вы можете использовать DevTools на настольном компьютере для отладки Chrome на Android, следуя инструкциям в разделе Удаленная отладка устройств Android .
Блокируйте сторонние файлы cookie в Chrome
Вы можете проверить, как FedCM работает без сторонних файлов cookie в Chrome, прежде чем он будет применен.
Чтобы заблокировать сторонние файлы cookie, используйте режим инкогнито или выберите «Блокировать сторонние файлы cookie» в настройках рабочего стола по адресу chrome://settings/cookies
или на мобильном устройстве, перейдя в «Настройки» > «Настройки сайта» > «Файлы cookie» .
Используйте API FedCM
Вы интегрируетесь с FedCM, создавая общеизвестный файл , файл конфигурации и конечные точки для списка учетных записей , выдачи утверждений и, при необходимости, метаданных клиента .
Отсюда FedCM предоставляет API-интерфейсы JavaScript, которые RP могут использовать для входа в систему с помощью IdP.
Создать известный файл
Чтобы предотвратить злоупотребление API трекерами , общеизвестный файл должен быть передан из /.well-known/web-identity
eTLD+1 IdP.
Например, если конечные точки IdP обслуживаются по адресу https://accounts.idp.example/
, они должны обслуживать общеизвестный файл по адресу https://idp.example/.well-known/web-identity
а также Конфигурационный файл IdP . Вот пример содержимого известного файла:
{
"provider_urls": ["https://accounts.idp.example/config.json"]
}
Файл JSON должен содержать свойство provider_urls
с массивом URL-адресов файлов конфигурации IdP , которые могут быть указаны как часть пути configURL
в navigator.credentials.get
с помощью RP . Количество строк URL-адресов в массиве ограничено одной, но это может измениться по вашему отзыву в будущем.
Создайте файл конфигурации 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;
Укажите полный URL-адрес расположения файла конфигурации IdP в качестве configURL
. Когда navigator.credentials.get()
вызывается на RP, браузер получает файл конфигурации с помощью запроса 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, который включает в себя следующие свойства:
Свойство | Описание |
---|---|
accounts_endpoint (обязательно) | URL-адрес конечной точки учетной записи . |
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 (необязательно) | Параметр брендинга, который устанавливает объект значка, отображаемый в диалоговом окне входа. Объект значка представляет собой массив с двумя параметрами:
|
RP может изменить строку в пользовательском интерфейсе диалогового окна FedCM, используя identity.context
для navigator.credentials.get()
чтобы учесть предопределенные контексты аутентификации. Необязательным свойством может быть одно из "signin"
(по умолчанию), "signup"
, "use"
или "continue"
.
Вот пример тела ответа от IdP:
{
"accounts_endpoint": "/accounts.php",
"client_metadata_endpoint": "/client_metadata.php",
"id_assertion_endpoint": "/assertion.php",
"disconnect_endpoint": "/disconnect.php",
"login_url": "/login",
"branding": {
"background_color": "green",
"color": "#FFEEAA",
"icons": [{
"url": "https://idp.example/icon.ico",
"size": 25
}]
}
}
Как только браузер получает файл конфигурации, он отправляет последующие запросы конечным точкам IdP:
Конечная точка аккаунтов
Конечная точка учетных записей IdP возвращает список учетных записей, в которые пользователь вошел в IdP. Если поставщик удостоверений поддерживает несколько учетных записей, эта конечная точка вернет все зарегистрированные учетные записи.
Браузер отправляет запрос GET
с файлами cookie с SameSite=None
, но без параметра client_id
, заголовка Origin
или заголовка Referer
. Это эффективно не позволяет IdP узнать, на какую RP пользователь пытается войти. Например:
GET /accounts.php HTTP/1.1
Host: accounts.idp.example
Accept: application/json
Cookie: 0x23223
Sec-Fetch-Dest: webidentity
Получив запрос, сервер должен:
- Убедитесь, что запрос содержит HTTP-заголовок
Sec-Fetch-Dest: webidentity
. - Сопоставьте файлы cookie сеанса с идентификаторами уже вошедших в систему учетных записей.
- Ответьте списком аккаунтов.
Браузер ожидает ответ 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 для фильтрации учетных записей. |
Пример тела ответа:
{
"accounts": [{
"id": "1234",
"given_name": "John",
"name": "John Doe",
"email": "john_doe@idp.example",
"picture": "https://idp.example/profile/123",
"approved_clients": ["123", "456", "789"],
"login_hints": ["demo1", "demo1@idp.example"]
}, {
"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", "demo2@idp.example"],
"domain_hints": ["corp.example"]
}]
}
Если пользователь не вошел в систему, ответьте HTTP 401 (неавторизованный).
Возвращенный список учетных записей используется браузером и не будет доступен RP.
Конечная точка метаданных клиента
Конечная точка метаданных клиента IdP возвращает метаданные проверяющей стороны, такие как политика конфиденциальности и условия обслуживания RP. RP должны заранее предоставить IdP ссылки на свою политику конфиденциальности и условия обслуживания. Эти ссылки отображаются в диалоговом окне входа, если пользователь еще не зарегистрировался на RP с IdP.
Браузер отправляет запрос GET
, используя client_id
navigator.credentials.get
без файлов cookie. Например:
GET /client_metadata.php?client_id=1234 HTTP/1.1
Host: accounts.idp.example
Origin: https://rp.example/
Accept: application/json
Sec-Fetch-Dest: webidentity
Получив запрос, сервер должен:
- Определите RP для
client_id
. - Ответьте метаданными клиента.
Свойства конечной точки метаданных клиента включают в себя:
Свойство | Описание |
---|---|
privacy_policy_url (необязательно) | URL-адрес политики конфиденциальности RP. |
terms_of_service_url (необязательно) | URL-адрес условий обслуживания RP. |
Браузер ожидает ответа JSON от конечной точки:
{
"privacy_policy_url": "https://rp.example/privacy_policy.html",
"terms_of_service_url": "https://rp.example/terms_of_service.html",
}
Возвращенные метаданные клиента используются браузером и не будут доступны RP.
Конечная точка утверждения идентификатора
Конечная точка утверждения идентификатора IdP возвращает утверждение для вошедшего в систему пользователя. Когда пользователь входит на веб-сайт RP с помощью вызова navigator.credentials.get()
, браузер отправляет POST
запрос с файлами cookie с SameSite=None
и типом контента application/x-www-form-urlencoded
в эту конечную точку с следующую информацию:
Свойство | Описание |
---|---|
client_id (обязательно) | Идентификатор клиента RP. |
account_id (обязательно) | Уникальный идентификатор вошедшего пользователя. |
nonce (необязательно) | Запрос nonce, предоставленный RP. |
disclosure_text_shown | Результатом является строка "true" или "false" (а не логическое значение). Результатом будет "false" если текст раскрытия не был показан. Это происходит, когда идентификатор клиента RP был включен в список свойств approved_clients ответа от конечной точки учетных записей или если браузер наблюдал момент регистрации в прошлом при отсутствии approved_clients . |
is_auto_selected | Если на RP выполняется автоматическая повторная аутентификация , is_auto_selected указывает "true" . В противном случае "false" . Это полезно для поддержки большего количества функций, связанных с безопасностью. Например, некоторые пользователи могут предпочесть более высокий уровень безопасности, который требует явного посредничества пользователя при аутентификации. Если IdP получает запрос токена без такого посредничества, он может обработать запрос по-другому. Например, верните код ошибки, чтобы RP мог снова вызвать API FedCM с помощью mediation: required . |
Пример HTTP-заголовка:
POST /assertion.php HTTP/1.1
Host: accounts.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=Ct60bD&disclosure_text_shown=true&is_auto_selected=true
Получив запрос, сервер должен:
- Ответьте на запрос с помощью CORS (совместное использование ресурсов между источниками) .
- Убедитесь, что запрос содержит HTTP-заголовок
Sec-Fetch-Dest: webidentity
. - Сопоставьте заголовок
Origin
с источником RP, определеннымclient_id
. Отклонить, если они не совпадают. - Сопоставьте
account_id
с идентификатором уже вошедшей в систему учетной записи. Отклонить, если они не совпадают. - Ответьте жетоном. Если запрос отклонен, ответьте сообщением об ошибке .
Способ выдачи токена зависит от поставщика удостоверений, но, как правило, он подписывается такой информацией, как идентификатор учетной записи, идентификатор клиента, происхождение эмитента, nonce
, чтобы RP мог проверить подлинность токена.
Браузер ожидает ответ JSON, который включает следующее свойство:
Свойство | Описание |
---|---|
token (обязательно) | Токен — это строка, содержащая утверждения об аутентификации. |
{
"token": "***********"
}
Возвращенный токен передается браузером RP, чтобы RP могла проверить аутентификацию.
Вернуть ответ об ошибке
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"
}
}
Отключить конечную точку
Вызывая IdentityCredential.disconnect()
, браузер отправляет POST
запрос между источниками с файлами cookie с SameSite=None
и типом контента application/x-www-form-urlencoded
в эту конечную точку отключения со следующей информацией:
Свойство | Описание |
---|---|
account_hint | Подсказка для учетной записи IdP.. |
client_id | Идентификатор клиента RP. |
POST /disconnect.php 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
Получив запрос, сервер должен:
- Ответьте на запрос с помощью CORS (совместное использование ресурсов между источниками) .
- Убедитесь, что запрос содержит HTTP-заголовок
Sec-Fetch-Dest: webidentity
. - Сопоставьте заголовок
Origin
с источником RP, определеннымclient_id
. Отклонить, если они не совпадают. - Сопоставьте
account_hint
с идентификаторами уже вошедших в систему учетных записей. - Отключите учетную запись пользователя от RP.
- Ответьте браузеру, указав идентифицированную информацию об учетной записи пользователя в формате JSON.
Пример полезной нагрузки JSON ответа выглядит следующим образом:
{
"account_id": "account456"
}
Вместо этого, если IdP желает, чтобы браузер отключил все учетные записи, связанные с RP, передайте строку, которая не соответствует ни одному идентификатору учетной записи, например "*"
.
URL-адрес входа
С помощью API статуса входа IdP должен сообщать браузеру статус входа пользователя. Однако статус может быть не синхронизирован, например, по истечении срока действия сеанса . В таком сценарии браузер может динамически разрешить пользователю входить в IdP через URL-адрес страницы входа, указанный в файле конфигурации idp login_url
.
В диалоговом окне FedCM отображается сообщение с предложением войти в систему, как показано на следующем рисунке.
Когда пользователь нажимает кнопку «Продолжить» , браузер открывает всплывающее окно со страницей входа в систему IdP.
Диалог представляет собой обычное окно браузера, в котором установлены основные файлы cookie. Что бы ни происходило в диалоговом окне, зависит от IdP, и нет доступных дескрипторов окон для отправки запроса на связь между источниками на странице RP. После того как пользователь вошел в систему, IdP должен:
- Отправьте заголовок
Set-Login: logged-in
или вызовите APInavigator.login.setStatus("logged-in")
чтобы сообщить браузеру, что пользователь выполнил вход. - Вызовите
IdentityProvider.close()
чтобы закрыть диалоговое окно.
Сообщите браузеру о статусе входа пользователя в поставщика удостоверений.
API статуса входа — это механизм, с помощью которого веб-сайт, особенно поставщик удостоверений личности, сообщает браузеру статус входа пользователя в поставщика удостоверений. С помощью этого API браузер может сократить количество ненужных запросов к IdP и снизить потенциальные атаки по времени.
IdP могут сообщать браузеру о статусе входа пользователя, отправляя HTTP-заголовок или вызывая API JavaScript, когда пользователь входит в систему IdP или когда пользователь выходит из всех своих учетных записей IdP. Для каждого IdP (идентифицированного по URL-адресу конфигурации) браузер сохраняет переменную с тремя состояниями, представляющую состояние входа в систему с возможными значениями: logged-in
, logged-out
» и unknown
. Состояние по умолчанию unknown
.
Чтобы сигнализировать о том, что пользователь вошел в систему, отправьте HTTP-заголовок Set-Login: logged-in
в навигации верхнего уровня или запрос подресурса того же сайта в источнике IdP:
Set-Login: logged-in
Альтернативно, вызовите API JavaScript navigator.login.setStatus("logged-in")
из источника IdP в навигации верхнего уровня:
navigator.login.setStatus("logged-in")
Эти вызовы записывают статус входа пользователя как logged-in
. Когда для статуса входа пользователя установлено logged-in
, RP, вызывающая FedCM, отправляет запросы к конечной точке учетных записей IdP и отображает доступные учетные записи пользователю в диалоговом окне FedCM.
Чтобы сигнализировать о том, что пользователь вышел из всех своих учетных записей, отправьте 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
. Когда статус входа пользователя в logged-out
, вызов FedCM автоматически завершается неудачей без выполнения запроса к конечной точке учетных записей IdP.
unknown
статус устанавливается до того, как поставщик удостоверений отправит сигнал с помощью API статуса входа. Unknown
был введен для более удобного перехода, поскольку пользователь мог уже войти в IdP на момент поставки этого API. У IdP может не быть возможности сообщить об этом браузеру к моменту первого вызова FedCM. В этом случае Chrome отправляет запрос к конечной точке учетных записей IdP и обновляет статус на основе ответа от конечной точки учетных записей:
- Если конечная точка возвращает список активных учетных записей, обновите статус до
logged-in
и откройте диалоговое окно FedCM, чтобы отобразить эти учетные записи. - Если конечная точка не возвращает учетных записей, обновите статус до
logged-out
и откажитесь от вызова FedCM.
Разрешить пользователю войти в систему с помощью динамического процесса входа.
Несмотря на то, что IdP продолжает сообщать браузеру статус входа пользователя, он может быть не синхронизирован, например, по истечении срока действия сеанса. Браузер пытается отправить запрос с учетными данными в конечную точку учетных записей, когда статус входа logged-in
, но сервер не возвращает учетные записи, поскольку сеанс больше не доступен. В таком случае браузер может динамически разрешить пользователю войти в IdP через всплывающее окно .
Войдите на проверяющую сторону с помощью поставщика удостоверений.
Как только конфигурация и конечные точки IdP станут доступны, RP могут вызвать navigator.credentials.get()
, чтобы запросить разрешение пользователям войти в RP с помощью IdP.
Перед вызовом API необходимо подтвердить, что FedCM доступен в браузере пользователя . Чтобы проверить, доступен ли FedCM, оберните этот код вокруг вашей реализации FedCM:
if ('IdentityCredential' in window) {
// If the feature is available, take action
}
Чтобы запросить разрешение пользователям войти в IdP от RP, выполните, например, следующие действия:
const credential = await navigator.credentials.get({
identity: {
providers: [{
configURL: 'https://accounts.idp.example/config.json',
clientId: '********',
nonce: '******'
}]
}
});
const { token } = credential;
Свойство providers
принимает массив объектов IdentityProvider
, которые имеют следующие свойства:
Свойство | Описание |
---|---|
configURL (обязательно) | Полный путь к файлу конфигурации IdP. |
clientId (обязательно) | Идентификатор клиента RP, выданный IdP. |
nonce (необязательно) | Случайная строка, гарантирующая выдачу ответа на этот конкретный запрос. Предотвращает повторные атаки. |
loginHint (необязательно) | Указав одно из значений login_hints , предоставленных конечными точками учетных записей , диалоговое окно FedCM выборочно отображает указанную учетную запись. |
domainHint (необязательно) | Указав одно из значений domain_hints , предоставленных конечными точками учетных записей , диалоговое окно FedCM выборочно отображает указанную учетную запись. |
Браузер по-разному обрабатывает варианты использования регистрации и входа в систему в зависимости от наличия approved_clients
в ответе от конечной точки списка учетных записей . Браузер не будет отображать текст раскрытия «Продолжить...», если пользователь уже зарегистрировался в RP.
Состояние регистрации определяется на основе того, выполнены или нет следующие условия:
- Если
approved_clients
включаютclientId
RP. - Если браузер помнит, что пользователь уже зарегистрировался на RP.
Когда RP вызывает navigator.credentials.get()
, происходят следующие действия:
- Браузер отправляет запросы и получает несколько документов:
- Известный файл и файл конфигурации IdP , которые объявляют конечные точки.
- Список аккаунтов .
- Необязательно: URL-адреса политики конфиденциальности и условий обслуживания RP, полученные из конечной точки метаданных клиента .
- Браузер отображает список учетных записей, которые пользователь может использовать для входа, а также условия обслуживания и политику конфиденциальности, если они доступны.
- Как только пользователь выбирает учетную запись для входа, запрос к конечной точке утверждения идентификатора отправляется IdP для получения токена.
- RP может проверить токен для аутентификации пользователя.
Ожидается, что RP будут поддерживать браузеры, которые не поддерживают FedCM, поэтому пользователи должны иметь возможность использовать существующий процесс входа, отличный от FedCM. Пока сторонние файлы cookie больше не будут доступны в браузерах, это не должно вызывать проблем.
Как только токен будет проверен сервером RP, RP может зарегистрировать пользователя или позволить ему войти в систему и начать новый сеанс.
API подсказок для входа в систему
После входа пользователя в систему иногда проверяющая сторона (RP) просит пользователя пройти повторную аутентификацию. Но пользователь может не быть уверен, какую учетную запись он использовал. Если RP может указать, с какой учетной записью войти в систему, пользователю будет проще выбрать учетную запись.
RP могут выборочно отображать конкретную учетную запись, вызывая navigator.credentials.get()
со свойством loginHint
с одним из значений login_hints
полученным из конечной точки списка учетных записей , как показано в следующем примере кода:
return await navigator.credentials.get({
identity: {
providers: [{
configURL: "https://idp.example/manifest.json",
clientId: "123",
nonce: nonce,
loginHint : "demo1@example.com"
}]
}
});
Если ни одна учетная запись не соответствует loginHint
, в диалоговом окне FedCM отображается приглашение для входа в систему, которое позволяет пользователю войти в учетную запись IdP, соответствующую подсказке, запрошенной RP. Когда пользователь нажимает на приглашение, открывается всплывающее окно с URL-адресом входа, указанным в файле конфигурации . Затем к ссылке добавляется подсказка для входа в систему и параметры запроса подсказки домена.
API подсказки домена
Бывают случаи, когда RP уже знает, что вход на сайт разрешен только учетным записям, связанным с определенным доменом. Это особенно распространено в корпоративных сценариях, где доступ к сайту ограничен корпоративным доменом. Чтобы обеспечить лучшее взаимодействие с пользователем, API FedCM позволяет RP отображать только те учетные записи, которые можно использовать для входа в RP. Это предотвращает сценарии, в которых пользователь пытается войти в RP, используя учетную запись за пределами корпоративного домена, но позже получает сообщение об ошибке (или молчание, если вход не сработал), поскольку не был использован правильный тип учетной записи.
RP могут выборочно отображать только совпадающие учетные записи, вызывая navigator.credentials.get()
со свойством domainHint
с одним из значений domain_hints
полученным из конечной точки списка учетных записей , как показано в следующем примере кода:
return await navigator.credentials.get({
identity: {
providers: [{
configURL: "https://idp.example/manifest.json",
clientId: "abc",
nonce: nonce,
domainHint : "corp.example"
}]
}
});
Если ни одна учетная запись не соответствует параметру domainHint
, в диалоговом окне FedCM отображается приглашение для входа в систему, которое позволяет пользователю войти в учетную запись IdP, соответствующую подсказке, запрошенной RP. Когда пользователь нажимает на приглашение, открывается всплывающее окно с URL-адресом входа, указанным в файле конфигурации . Затем к ссылке добавляется подсказка для входа в систему и параметры запроса подсказки домена.
Показать сообщение об ошибке
Иногда поставщик удостоверений не может выдать токен по законным причинам, например, когда клиент неавторизован, сервер временно недоступен. Если IdP возвращает ответ «ошибка», RP может его перехватить, а Chrome уведомляет пользователя, показывая пользовательский интерфейс браузера с информацией об ошибке, предоставленной IdP.
try {
const cred = await navigator.credentials.get({
identity: {
providers: [
{
configURL: "https://idp.example/manifest.json",
clientId: "1234",
},
],
}
});
} catch (e) {
const code = e.code;
const url = e.url;
}
Автоматическая повторная аутентификация пользователей после первоначальной аутентификации
Автоматическая повторная аутентификация FedCM («автоматическая повторная аутентификация» вкратце) может позволить пользователям автоматически проходить повторную аутентификацию, когда они возвращаются после первоначальной аутентификации с использованием FedCM. «Первоначальная аутентификация» здесь означает, что пользователь создает учетную запись или входит на веб-сайт RP, впервые нажав кнопку «Продолжить как...» в диалоговом окне входа FedCM в одном и том же экземпляре браузера.
Хотя явный пользовательский опыт имеет смысл до того, как пользователь создал федеративную учетную запись, чтобы предотвратить отслеживание (что является одной из основных целей FedCM), он становится излишне громоздким после того, как пользователь прошел через это один раз: после того, как пользователь предоставляет разрешение на разрешение связи между RP и IdP, нет никаких преимуществ конфиденциальности или безопасности для принудительного подтверждения другого явного пользователя для чего-то, что он уже ранее подтвердил.
При автоматической повторной аутентификации браузер меняет свое поведение в зависимости от параметра, который вы указываете для mediation
при вызове navigator.credentials.get()
.
const cred = await navigator.credentials.get({
identity: {
providers: [{
configURL: "https://idp.example/fedcm.json",
clientId: "1234",
}],
},
mediation: 'optional', // this is the default
});
// `isAutoSelected` is `true` if auto-reauthn was performed.
const isAutoSelected = cred.isAutoSelected;
mediation
— это свойство API управления учетными данными . Оно ведет себя так же, как и для PasswordCredential и FederatedCredential , а также частично поддерживается PublicKeyCredential . Свойство принимает следующие четыре значения:
-
'optional'
(по умолчанию): если возможно, выполняется автоматическая повторная аутентификация, в противном случае требуется посредничество. Мы рекомендуем выбрать эту опцию на странице входа. -
'required'
: для продолжения всегда требуется посредничество, например нажатие кнопки «Продолжить» в пользовательском интерфейсе. Выберите этот вариант, если ожидается, что ваши пользователи будут явно предоставлять разрешение каждый раз, когда им необходимо пройти аутентификацию. -
'silent'
: если возможно, выполните автоматическую повторную аутентификацию, в противном случае — молчаливый сбой, не требуя посредничества. Мы рекомендуем выбирать этот параметр на страницах, отличных от специальной страницы входа, но на которых вы хотите, чтобы пользователи оставались в системе, например на странице товара на веб-сайте доставки или странице статьи на новостном веб-сайте. -
'conditional'
: используется для WebAuthn и на данный момент недоступен для FedCM.
При этом вызове автоматическая повторная аутентификация происходит при следующих условиях:
- FedCM доступен для использования. Например, пользователь не отключил FedCM ни глобально , ни для RP в настройках.
- Пользователь использовал только одну учетную запись с FedCM API для входа на веб-сайт в этом браузере.
- Пользователь входит в IdP с этой учетной записью.
- Автоматическая повторная аутентификация не произошла в течение последних 10 минут.
- RP не вызвал
navigator.credentials.preventSilentAccess()
после предыдущего входа в систему.
При выполнении этих условий попытка автоматической повторной аутентификации пользователя начинается сразу после вызова FedCM navigator.credentials.get()
.
При mediation: optional
автоматическая повторная аутентификация может быть недоступна по причинам, известным только браузеру; RP может проверить, выполняется ли автоматическая повторная аутентификация, проверив свойство isAutoSelected
.
Это полезно для оценки производительности API и соответствующего улучшения UX. Кроме того, когда он недоступен, пользователю может быть предложено войти в систему с явным посредничеством пользователя, которое представляет собой поток с mediation: required
.
Принудительное посредничество с помощью preventSilentAccess()
Автоматическая повторная аутентификация пользователей сразу после выхода из системы не обеспечит хорошего пользовательского опыта. Вот почему FedCM имеет 10-минутный период молчания после автоматической повторной аутентификации, чтобы предотвратить такое поведение. Это означает, что автоматическая повторная аутентификация происходит не чаще одного раза в 10 минут, если только пользователь не войдет в систему повторно в течение 10 минут. RP должна вызвать navigator.credentials.preventSilentAccess()
, чтобы явно запросить браузер отключить автоматическую повторную аутентификацию, когда пользователь явно выходит из RP, например, нажав кнопку выхода.
function signout() {
navigator.credentials.preventSilentAccess();
location.href = '/signout';
}
Пользователи могут отказаться от автоматической повторной аутентификации в настройках.
Пользователи могут отказаться от автоматической повторной аутентификации в меню настроек:
- В настольном Chrome перейдите в
chrome://password-manager/settings
> Войти автоматически. - В Android Chrome откройте «Настройки» > «Менеджер паролей» > нажмите на шестеренку в правом верхнем углу > «Автоматический вход».
Отключив переключатель, пользователь может полностью отказаться от автоматической повторной аутентификации. Этот параметр сохраняется и синхронизируется на всех устройствах, если пользователь вошел в учетную запись Google на экземпляре Chrome и включена синхронизация.
Отключите IdP от RP
Если пользователь ранее вошел в RP, используя IdP через FedCM, отношения запоминаются браузером локально в виде списка подключенных учетных записей. RP может инициировать отключение, вызвав функцию IdentityCredential.disconnect()
. Эту функцию можно вызвать из кадра RP верхнего уровня. RP необходимо пропустить configURL
, clientId
, который он использует в IDP, и accountHint
для отключения IDP. Подсказка для учетной записи может быть произвольной строкой, если конечная точка отключения может идентифицировать учетную запись, например, адрес электронной почты или идентификатор пользователя, который не обязательно соответствует идентификатору учетной записи, который предоставил конечная точка списка учетной записи:
// Disconnect an IdP account "account456" from the RP "https://idp.com/". This is invoked on the RP domain.
IdentityCredential.disconnect({
configURL: "https://idp.com/config.json",
clientId: "rp123",
accountHint: "account456"
});
IdentityCredential.disconnect()
возвращает Promise
. Это обещание может вызвать исключение по следующим причинам:
- Пользователь не вписался в RP, используя IDP через FedCM.
- API вызывается из IFRAME без политики разрешений FEDCM.
- Конфигурация недействительна или отсутствует конечная точка отключения.
- Политика безопасности контента (CSP) Проверка не удастся.
- Существует ожидающий запрос отключения.
- Пользователь отключил FedCM в настройках браузера.
Когда конечная точка отключения IDP возвращает ответ , RP и IDP отключены в браузере, и обещание разрешено. Идентификатор отключенных счетов указан в ответе от конечной точки отключения .
Позвоните Fedcm из перекрестного происхождения
FEDCM может быть вызван из перекрестного происхождения IFRAME, используя политику разрешений identity-credentials-get
, если это позволяет это родительская кадр. Для этого добавьте атрибут allow="identity-credentials-get"
к тегу iframe следующим образом:
<iframe src="https://fedcm-cross-origin-iframe.glitch.me" allow="identity-credentials-get"></iframe>
Вы можете увидеть это в действии в примере .
При желании, если родительский кадр хочет ограничить происхождение, чтобы позвонить в FEDCM, отправьте заголовок Permissions-Policy
со списком разрешенных источников.
Permissions-Policy: identity-credentials-get=(self "https://fedcm-cross-origin-iframe.glitch.me")
Вы можете узнать больше о том, как работает политика разрешений в управлении функциями браузера с политикой разрешений .
,Узнайте, как использовать FEDCM для конфиденциальности Федерации личности.
FEDCM (Federated Decriention Management) -это подход, сохраняющий конфиденциальность, к федеративным услугам идентификации (например, «Войдите с ...»), где пользователи могут войти в сайты, не делясь своей личной информацией с службой идентификации или на сайте.
Чтобы узнать больше о вариантах использования FEDCM, потоках пользователей и дорожной карте API, ознакомьтесь с введением в API FEDCM .
Среда развития FEDCM
Вам нужен безопасный контекст (HTTPS или Localhost) как на IDP, так и на RP в Chrome, чтобы использовать FEDCM.
Код отладки на Chrome на Android
Установите и запустите сервер локально для отладки вашего кода FedCM. Вы можете получить доступ к этому серверу в Chrome на устройстве Android, подключенном с помощью USB -кабеля с переадресацией порта.
Вы можете использовать DevTools на рабочем столе для отладки Chrome на Android, следуя инструкциям на устройствах Android отладки .
Блокировать сторонние печенья на Chrome
Вы можете проверить, как работает FedCM без сторонних файлов cookie на Chrome, прежде чем он на самом деле соблюдается.
Чтобы заблокировать сторонние файлы cookie, используйте режим Incognito или выберите «Блок сторонних файлов cookie» в настройках рабочего стола на chrome://settings/cookies
или на мобильном телефоне, перейдя к настройкам > Настройки сайта > Cookie .
Используйте API FEDCM
Вы интегрируете с FEDCM, создавая хорошо известный файл , файл конфигурации и конечные точки для списка учетных записей , выдачи утверждения и необязательно метаданные клиента .
Оттуда FedCM раскрывает API JavaScript, которые RPS может использовать для регистрации с IDP.
Создать известный файл
Чтобы не допустить, чтобы трекеры злоупотребляли API , необходимо подавать хорошо известный файл от /.well-known/web-identity
of Etld+1 IDP.
Например, если конечные точки IDP обслуживаются в соответствии с https://accounts.idp.example/
, они должны обслуживать хорошо известный файл по адресу https://idp.example/.well-known/web-identity
а также Файл конфигурации IDP . Вот пример известного содержимого файла:
{
"provider_urls": ["https://accounts.idp.example/config.json"]
}
Файл JSON должен содержать свойство provider_urls
с массивом URL -файлов конфигурации IDP , которые можно указать как часть configURL
в navigator.credentials.get
by RPS . Количество строк URL в массиве ограничено одним, но это может измениться с вашей обратной связью в будущем.
Создать файл конфигурации IDP и конечные точки
Файл конфигурации IDP предоставляет список необходимых конечных точек для браузера. IDPs будут размещать этот файл конфигурации и необходимые конечные точки и URL -адреса. Все ответы JSON должны быть поданы с application/json
Content-Type.
URL -адрес файла конфигурации определяется значениями, предоставленными для navigator.credentials.get
CALL, выполненного на RP .
const credential = await navigator.credentials.get({
identity: {
context: 'signup',
providers: [{
configURL: 'https://accounts.idp.example/config.json',
clientId: '********',
nonce: '******'
}]
}
});
const { token } = credential;
Укажите полный URL -адрес расположения файла конфигурации IDP в качестве configURL
. Когда navigator.credentials.get()
вызывается в RP, браузер получает файл конфигурации с запросом GET
без заголовка Origin
или заголовка Referer
. Запрос не имеет файлов cookie и не следует перенаправлениям. Это эффективно предотвращает обучение IDP, кто сделал запрос и какой RP пытается подключиться. Например:
GET /config.json HTTP/1.1
Host: accounts.idp.example
Accept: application/json
Sec-Fetch-Dest: webidentity
Браузер ожидает ответа JSON от IDP, который включает в себя следующие свойства:
Свойство | Описание |
---|---|
accounts_endpoint (требуется) | URL для конечной точки счетов . |
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 - это массив с двумя параметрами:
|
RP может изменить строку в пользовательском интерфейсе диалога FEDCM, используя значение identity.context
для navigator.credentials.get()
для размещения предопределенных контекстов аутентификации. Необязательное свойство может быть одним из "signin"
(по умолчанию), "signup"
, "use"
или "continue"
.
Вот пример ответа тела от IDP:
{
"accounts_endpoint": "/accounts.php",
"client_metadata_endpoint": "/client_metadata.php",
"id_assertion_endpoint": "/assertion.php",
"disconnect_endpoint": "/disconnect.php",
"login_url": "/login",
"branding": {
"background_color": "green",
"color": "#FFEEAA",
"icons": [{
"url": "https://idp.example/icon.ico",
"size": 25
}]
}
}
После того, как браузер извлекает файл конфигурации, он отправляет последующие запросы в конечные точки IDP:
Счетная конечная точка
Конечная точка учетных записей IDP возвращает список учетных записей, в которые пользователь вписался на IDP. Если IDP поддерживает несколько учетных записей, эта конечная точка вернет все подписанные в учетных записях.
Браузер отправляет запрос GET
с помощью файлов cookie с SameSite=None
, но без параметра client_id
, заголовка Origin
или заголовка Referer
. Это эффективно предотвращает IDP от изучения RP, к которому пользователь пытается войти. Например:
GET /accounts.php HTTP/1.1
Host: accounts.idp.example
Accept: application/json
Cookie: 0x23223
Sec-Fetch-Dest: webidentity
При получении запроса сервер должен:
- Убедитесь, что запрос содержит испытания
Sec-Fetch-Dest: webidentity
. - Сопоставьте сеанс cookie с идентификаторами уже подписанных учетных записей.
- Ответьте списком учетных записей.
Браузер ожидает ответа 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 для фильтрации учетных записей. |
Пример ответа тела:
{
"accounts": [{
"id": "1234",
"given_name": "John",
"name": "John Doe",
"email": "john_doe@idp.example",
"picture": "https://idp.example/profile/123",
"approved_clients": ["123", "456", "789"],
"login_hints": ["demo1", "demo1@idp.example"]
}, {
"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", "demo2@idp.example"],
"domain_hints": ["corp.example"]
}]
}
Если пользователь не подписан, ответьте HTTP 401 (несанкционированный).
Возвращенный список учетных записей потребляется браузером и не будет доступен для RP.
Конечная точка метаданных клиентов
Конечная точка метаданных клиентов IDP возвращает метаданные полаженной стороны, такие как Политика конфиденциальности RP и условия обслуживания. RPS должен заранее предоставлять ссылки на их политику конфиденциальности и условия обслуживания. Эти ссылки отображаются в диалоговом окне входа, когда пользователь еще не зарегистрировался на RP с IDP.
Браузер отправляет запрос GET
с помощью client_id
navigator.credentials.get
без файлов cookie. Например:
GET /client_metadata.php?client_id=1234 HTTP/1.1
Host: accounts.idp.example
Origin: https://rp.example/
Accept: application/json
Sec-Fetch-Dest: webidentity
При получении запроса сервер должен:
- Определите RP для
client_id
. - Ответьте метаданными клиентами.
Свойства конечной точки метаданных клиентов включают:
Свойство | Описание |
---|---|
privacy_policy_url (необязательно) | RP URL политики конфиденциальности. |
terms_of_service_url (необязательно) | RP УРГОВЫЕ УРЛ. |
Браузер ожидает ответа JSON от конечной точки:
{
"privacy_policy_url": "https://rp.example/privacy_policy.html",
"terms_of_service_url": "https://rp.example/terms_of_service.html",
}
Возвращенные метаданные клиента потребляются браузером и не будут доступны для RP.
Идентификационное утверждение конечная точка
Конечная точка идентификатора IDP возвращает утверждение для своего подписанного пользователя. Когда пользователь войдет на веб-сайт RP с использованием вызова navigator.credentials.get()
, браузер отправляет запрос POST
с помощью файлов cookie с SameSite=None
и типа контента application/x-www-form-urlencoded
в эту конечную точку Следующая информация:
Свойство | Описание |
---|---|
client_id (требуется) | Идентификатор клиента RP. |
account_id (требуется) | Уникальный идентификатор подписания в пользователе. |
nonce (необязательно) | Запрос, не подходящий, предоставленный RP. |
disclosure_text_shown | Приводит к строке "true" или "false" (а не логии). Результатом является "false" если текст раскрытия не был показан. Это происходит, когда идентификатор клиента RP был включен в список свойств approved_clients ответа с конечной точки учетных записей или если браузер наблюдал момент регистрации в прошлом в отсутствие approved_clients . |
is_auto_selected | Если на RP выполняется автоматическая реконструкция , is_auto_selected указывает "true" . В противном случае "false" . Это полезно для поддержки большего количества функций, связанных с безопасностью. Например, некоторые пользователи могут предпочесть более высокий уровень безопасности, который требует явного посредничества пользователей в аутентификации. Если IDP получает запрос токена без такого посредничества, они могут обрабатывать запрос по -разному. Например, верните код ошибки, чтобы RP мог снова вызвать API FedCM с помощью mediation: required . |
Пример заголовка http:
POST /assertion.php HTTP/1.1
Host: accounts.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=Ct60bD&disclosure_text_shown=true&is_auto_selected=true
При получении запроса сервер должен:
- Ответьте на запрос с CORS (совместное использование ресурсов по перекрестному происхождению) .
- Убедитесь, что запрос содержит испытания
Sec-Fetch-Dest: webidentity
. - Сопоставьте заголовок
Origin
против RP Origin, определяяclient_id
. Отвергай, если они не совпадают. - Match
account_id
против идентификатора уже подписанной учетной записи. Отвергай, если они не совпадают. - Ответьте с токеном. Если запрос отклонен, ответьте ответом на ошибку .
То, как выдается токен, зависит от IDP, но в целом он подписан с такой информацией, как идентификатор учетной записи, идентификатор клиента, происхождение эмитента, nonce
, так что RP может проверить токен, является подлинным.
Браузер ожидает ответа JSON, который включает в себя следующее свойство:
Свойство | Описание |
---|---|
token (требуется) | Токен - это строка, которая содержит претензии об аутентификации. |
{
"token": "***********"
}
Возвращенный токен передается в RP браузером, так что RP может проверить аутентификацию.
Вернуть ответ ошибки
id_assertion_endpoint
также может вернуть ответ «ошибки», который имеет два дополнительных поля:
-
code
: IDP может выбрать одну из известных ошибок из указанного списка ошибок OAuth 2.0 (invalid_request
,unauthorized_client
,access_denied
,server_error
иtemporarily_unavailable
) или использовать любую произвольную строку. Если последнее, Chrome делает пользовательский интерфейс ошибки с общим сообщением об ошибке и передайте код в RP. -
url
: он идентифицирует веб-страницу, читаемую человеку с информацией об ошибке, чтобы предоставить дополнительную информацию об ошибке пользователям. Это поле полезно для пользователей, потому что браузеры не могут предоставить богатые сообщения об ошибках в встроенном пользовательском интерфейсе. Например: ссылки для следующих шагов или контактная информация о обслуживании клиентов. Если пользователь хочет узнать больше о деталях ошибок и о том, как ее исправить, он может посетить предоставленную страницу из пользовательского интерфейса браузера для получения более подробной информации. URL должен быть одинакового сайта, что и IDPconfigURL
.
// id_assertion_endpoint response
{
"error" : {
"code": "access_denied",
"url" : "https://idp.example/error?type=access_denied"
}
}
Отключите конечную точку
Вызывая IdentityCredential.disconnect()
, браузер отправляет запрос POST
перекрестного происхождения с помощью файлов cookie с SameSite=None
и контент-тип application/x-www-form-urlencoded
с этой отключением конечной точки со следующей информацией:
Свойство | Описание |
---|---|
account_hint | Подсказка для учетной записи IDP .. |
client_id | Идентификатор клиента RP. |
POST /disconnect.php 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
При получении запроса сервер должен:
- Ответьте на запрос с CORS (совместное использование ресурсов по перекрестному происхождению) .
- Убедитесь, что запрос содержит испытания
Sec-Fetch-Dest: webidentity
. - Сопоставьте заголовок
Origin
против RP Origin, определяяclient_id
. Отвергай, если они не совпадают. - Match
account_hint
против идентификаторов уже подписанных учетных записей. - Отключите учетную запись пользователя от RP.
- Ответьте на браузер с идентифицированной информацией об учетной записи пользователя в формате JSON.
Пример ответа json полезной нагрузки выглядит так:
{
"account_id": "account456"
}
Вместо этого, если IDP желает браузера отключить все учетные записи, связанные с RP, передайте строку, которая не соответствует ни одному идентификатору учетной записи, например "*"
.
Вход в систему URL
С помощью API состояния входа в систему IDP должен информировать состояние входа пользователя в браузер. Тем не менее, статус может быть вне синхронизации, например, когда сеанс истекает . В таком сценарии браузер может динамически позволить пользователю войти в IDP через login_url
-адрес страницы входа, указанный с помощью файла конфигурации IDP .
Диалог FEDCM отображает сообщение, предлагающее знак, как показано на следующем изображении.
Когда пользователь нажимает кнопку «Продолжить» , браузер открывает всплывающее окно для страницы входа в систему IDP.
Диалог-это обычное окно браузера, в котором есть первоклассные печенья. Все, что происходит в диалоговом окне, связано с IDP, и не доступны ручки для оконных окон для перекрестного запроса общения на странице RP. После того, как пользователь вписался, IDP должен:
- Отправьте
Set-Login: logged-in
или вызовите APInavigator.login.setStatus("logged-in")
чтобы сообщить о браузере, что пользователь был подписан. - Вызовите
IdentityProvider.close()
чтобы закрыть диалог.
Сообщите браузеру о статусе входа пользователя на поставщике идентификации
API статуса входа в систему - это механизм, в котором веб -сайт, особенно IDP, информирует браузер о состоянии входа пользователя на IDP. С помощью этого API браузер может уменьшить ненужные запросы на IDP и смягчить потенциальные атаки времени.
IDP могут сигнализировать о статусе входа пользователя в браузер, отправив заголовок HTTP или вызывая API JavaScript, когда пользователь вписался на IDP или когда пользователь подписывается со всех своих учетных записей IDP. Для каждого IDP (идентифицированного по URL-адресу конфигурации) браузер сохраняет переменную Tri-State, представляющую состояние входа с возможными значениями, logged-in
, logged-out
и unknown
. Состояние по умолчанию unknown
.
Чтобы сигнализировать о том, что пользователь вписывается, отправьте заголовок Set-Login: logged-in
HTTP в навигации на верхнем уровне или в одном месте Subresource запрос на IDP Origin:
Set-Login: logged-in
В качестве альтернативы, вызовите JavaScript API navigator.login.setStatus("logged-in")
из происхождения IDP в навигации верхнего уровня:
navigator.login.setStatus("logged-in")
Эти вызовы записывают состояние входа пользователя в качестве logged-in
. Когда статус входа пользователя будет установлен для logged-in
, RP Calling FedCM делает запросы на конечную точку учетных записей IDP и отображает доступные учетные записи пользователю в диалоговом окне FEDCM.
Чтобы сигнализировать о том, что пользователь подписан из всех их учетных записей, отправьте 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
. Когда статус входа пользователя logged-out
, вызов FEDCM молча не выполняется, не выполняя запрос на конечную точку учетных записей IDP.
unknown
статус устанавливается до того, как IDP отправляет сигнал, используя API состояния входа в систему. Unknown
был введен для лучшего перехода, потому что пользователь, возможно, уже подписал в IDP, когда этот API был отправлен. У IDP может не быть возможности сигнализировать об этом в браузер к тому времени, когда FedCM впервые вызван. В этом случае Chrome делает запрос на конечную точку счетов IDP и обновите состояние на основе ответа с конечной точки учетных записей:
- Если конечная точка возвращает список активных учетных записей, обновите статус для
logged-in
и откройте диалог FEDCM, чтобы показать эти учетные записи. - Если конечная точка возвращает никаких учетных записей, обновите статус для
logged-out
и сбой вызова FEDCM.
Пусть пользователь войдет через динамический поток входа в систему
Несмотря на то, что IDP продолжает информировать статус входа пользователя в браузер, он может быть вне синхронизации, например, когда срок действия сеанса истекает. Браузер пытается отправить запрос на учетные данные в конечную точку учетных записей, когда статус входа в систему logged-in
, но сервер возвращает никаких учетных записей, поскольку сеанс больше не доступен. В таком сценарии браузер может динамически позволить пользователю войти в IDP через всплывающее окно .
Войдите в сторону полагаться с поставщиком личности
После того, как конфигурация и конечные точки IDP будут доступны, RPS может вызвать navigator.credentials.get()
для запроса, позволяя пользователям войти в RP с IDP.
Перед вызовом API вам необходимо подтвердить, что FedCM доступен в браузере пользователя . Чтобы проверить, доступен ли FedCM, оберните этот код вокруг вашей реализации FEDCM:
if ('IdentityCredential' in window) {
// If the feature is available, take action
}
Чтобы запросить, чтобы пользователи могли войти в IDP из RP, сделайте следующее, например:
const credential = await navigator.credentials.get({
identity: {
providers: [{
configURL: 'https://accounts.idp.example/config.json',
clientId: '********',
nonce: '******'
}]
}
});
const { token } = credential;
Собственность providers
принимает множество объектов IdentityProvider
, которые имеют следующие свойства:
Свойство | Описание |
---|---|
configURL (требуется) | Полный путь файла конфигурации IDP. |
clientId (требуется) | Идентификатор клиента RP, выпущенный IDP. |
nonce (необязательно) | Случайная строка для обеспечения выдачи ответа для этого конкретного запроса. Предотвращает атаки воспроизведения. |
loginHint (необязательно) | Указав одно из значений login_hints предоставленных конечными точками учетных записей , диалог FEDCM выборочно показывает указанную учетную запись. |
domainHint (необязательно) | Указав одно из значений domain_hints предоставленных конечными точками учетных записей , диалог FEDCM выбирает указанную учетную запись. |
Браузер обрабатывает варианты регистрации и входа в систему использования по-разному в зависимости от существования approved_clients
в ответе из конечной точки списка учетных записей . Браузер не будет отображать текст раскрытия «для продолжения ...», если пользователь уже подписался на RP.
Состояние регистрации определяется на основе того, выполняются ли следующие условия или нет:
- Если
approved_clients
включаютclientId
RP. - Если браузер вспоминает, что пользователь уже подписался на RP.
Когда RP вызывает navigator.credentials.get()
, проводятся следующие действия:
- Браузер отправляет запросы и получает несколько документов:
- Хорошо известный файл и файл конфигурации IDP , который объявляет конечные точки.
- Список счетов .
- Необязательно: URL -адреса для Политики конфиденциальности и условий обслуживания RP, извлеченных из конечной точки метаданных клиентов .
- Браузер отображает список учетных записей, которые пользователь может использовать для регистрации, а также Условия обслуживания и политики конфиденциальности, если таковые имеются.
- После того, как пользователь выбирает учетную запись, в которой можно войти в систему, запрос на конечную точку утверждения идентификатора отправляется на IDP для извлечения токена.
- RP может проверить токен для аутентификации пользователя.
Ожидается, что RP будут поддерживать браузеры, которые не поддерживают FedCM, поэтому пользователи должны иметь возможность использовать существующий процесс входа без FEDCM. До тех пор, пока сторонние файлы cookie больше не доступны в браузерах, это должно оставаться непроблеменным.
Как только токен будет подтвержден RP-сервером, RP может зарегистрировать пользователя или позволить им входить в систему и запустить новый сеанс.
Логин подсказка API
После того, как пользователь входит, иногда полаженная сторона (RP) просит пользователя повторно. Но пользователь может не быть уверен, какую учетную запись они использовали. Если RP может указать, с какой учетной записью следует войти в систему, пользователю будет легче выбрать учетную запись.
RPS может выборочно показать конкретную учетную запись, вызывая navigator.credentials.get()
с свойством loginHint
с одним из значений login_hints
извлеченных из конечной точки списка учетных записей , как показано в следующем примере кода:
return await navigator.credentials.get({
identity: {
providers: [{
configURL: "https://idp.example/manifest.json",
clientId: "123",
nonce: nonce,
loginHint : "demo1@example.com"
}]
}
});
Когда учетные записи не соответствуют loginHint
, в диалоговом окне FEDCM показана подсказка для входа в систему, которая позволяет пользователю войти в учетную запись IDP, соответствующую подсказке, запрошенной RP. Когда пользователь нажимает на подсказку, всплывающее окно открывается с помощью URL -адреса входа, указанного в файле конфигурации . Затем ссылка добавляется с подсказкой для входа в систему и параметрами запроса домена.
Домен подсказка API
Есть случаи, когда RP уже знает, что только учетные записи, связанные с определенным доменом, разрешаются войти на сайт. Это особенно распространено в сценариях предприятия, в которых доступ к сайту ограничивается корпоративным доменом. Чтобы обеспечить лучший пользовательский опыт, API FEDCM позволяет RP показывать только учетные записи, которые могут использоваться для входа в RP. Это предотвращает сценарии, в которых пользователь пытается войти в RP, используя учетную запись за пределами корпоративного домена, только для того, чтобы быть обслуживаемым с сообщением об ошибке позже (или молчанием, где логин не работал), потому что правильный тип учетной записи не использовался.
RPS может выборочно отображать только соответствующие учетные записи, вызывая navigator.credentials.get()
с свойством domainHint
с одним из значений domain_hints
извлеченных из конечной точки списка учетных записей , как показано в следующем примере кода:
return await navigator.credentials.get({
identity: {
providers: [{
configURL: "https://idp.example/manifest.json",
clientId: "abc",
nonce: nonce,
domainHint : "corp.example"
}]
}
});
Когда учетные записи не соответствуют domainHint
, в диалоговом окне FEDCM показана подсказка для входа в систему, которая позволяет пользователю войти в учетную запись IDP, соответствующую подсказке, запрашиваемой RP. Когда пользователь нажимает на подсказку, всплывающее окно открывается с помощью URL -адреса входа, указанного в файле конфигурации . Затем ссылка добавляется с подсказкой для входа в систему и параметрами запроса домена.
Показать сообщение об ошибке
Иногда IDP может не иметь возможности выпустить токен по законным причинам, например, когда клиент неавторизован, сервер временно недоступен. Если IDP возвращает ответ «ошибки», RP может поймать его, а также Chrome уведомляет пользователя, отображая интерфейс браузера с информацией об ошибке, предоставленной IDP.
try {
const cred = await navigator.credentials.get({
identity: {
providers: [
{
configURL: "https://idp.example/manifest.json",
clientId: "1234",
},
],
}
});
} catch (e) {
const code = e.code;
const url = e.url;
}
Пользователи автоматической резоляции после первоначальной аутентификации
Короче говоря, Auto-Reautentication FedCM («Автозатог» может позволить пользователям автоматически повторно повторно навредить, когда они возвращаются после своей первоначальной аутентификации с использованием FEDCM. «Первоначальная аутентификация» означает, что пользователь создает учетную запись или знаки на веб-сайте RP, нажав кнопку «Продолжить как ...» на диалоговом окне «Продолжить ...» на диалоговом окне «Продолжить ...» в диалоговом окне «Переход» FEDCM впервые в том же экземпляре браузера.
Хотя явный пользовательский опыт имеет смысл до того, как пользователь создал федеративную учетную запись для предотвращения отслеживания (которая является одной из основных целей FedCM), она излишне громоздко после того, как пользователь прошел через него один раз: после того, как пользователь предоставит разрешение разрешить разрешение Коммуникация между RP и IDP, нет никакой конфиденциальности или обеспечения безопасности для обеспечения соблюдения другого явного подтверждения пользователя для чего -то, что они уже признали ранее.
С помощью Auto-Reauthn браузер меняет свое поведение в зависимости от опции, который вы указываете для mediation
при вызове navigator.credentials.get()
.
const cred = await navigator.credentials.get({
identity: {
providers: [{
configURL: "https://idp.example/fedcm.json",
clientId: "1234",
}],
},
mediation: 'optional', // this is the default
});
// `isAutoSelected` is `true` if auto-reauthn was performed.
const isAutoSelected = cred.isAutoSelected;
mediation
- это свойство в API управления учетными данными , оно ведет себя так же, как и для PasswordCredential и FederatedCredential , а также частично поддерживается PublicKeyCredential . Собственность принимает следующие четыре значения:
-
'optional'
(по умолчанию): автоматическое восстановление, если это возможно, требует посредничества, если нет. Мы рекомендуем выбрать эту опцию на странице входа. -
'required'
: всегда требуется посредничество, например, нажав кнопку «Продолжить» на пользовательском интерфейсе. Выберите эту опцию, если ожидается, что ваши пользователи будут давать разрешение явно каждый раз, когда они должны быть аутентифицированы. -
'silent'
: автоматическое восстановление, если это возможно, молча терпит неудачу, не требуя посредничества, если нет. Мы рекомендуем выбрать эту опцию на страницах, отличных от выделенной страницы входа, но где вы хотите подписаться пользователями, например, на странице предметов на веб-сайте доставки или на странице статьи на новостном сайте. -
'conditional'
: используется для Webauthn и не доступен для FedCM в данный момент.
С помощью этого звонка Auto-Reauthn происходит в следующих условиях:
- FedCM доступен для использования. Например, пользователь не отключил FedCM ни глобально , ни для RP в настройках.
- Пользователь использовал только одну учетную запись с FedCM API для регистрации на веб -сайте в этом браузере.
- Пользователь подписан в IDP с этой учетной записью.
- Авто-восстановление не произошло в течение последних 10 минут.
- RP не назвал
navigator.credentials.preventSilentAccess()
после предыдущего входа.
Когда эти условия будут выполнены, попытка автоматически повторно повторно нанести пользователь начинается, как только используется Fedcm navigator.credentials.get()
.
При mediation: optional
, автоматическое восстановление может быть недоступным по причинам, которые знают только браузер; RP может проверить, выполняется ли автоматическая реатен, изучая isAutoSelected
Property.
This is helpful to evaluate the API performance and improve UX accordingly. Also, when it's unavailable, the user may be prompted to sign in with explicit user mediation, which is a flow with mediation: required
.
Enforce mediation with preventSilentAccess()
Auto-reauthenticating users immediately after they sign out wouldn't make for a very good user experience. That's why FedCM has a 10-minute quiet period after an auto-reauthn to prevent this behavior. This means that auto-reauthn happens at most once in every 10-minutes unless the user signs back in within 10-minutes. The RP should call navigator.credentials.preventSilentAccess()
to explicitly request the browser to disable auto-reauthn when a user signs out of the RP explicitly, for example, by clicking a sign-out button.
function signout() {
navigator.credentials.preventSilentAccess();
location.href = '/signout';
}
Users can opt-out of auto-reauthn in settings
Users can opt-out from auto-reauth from the settings menu:
- On desktop Chrome, go to
chrome://password-manager/settings
> Sign in automatically. - On Android Chrome, open Settings > Password Manager > Tap on a cog at the top right corner > Auto sign-in.
By disabling the toggle, the user can opt-out from auto-reauthn behavior all together. This setting is stored and synchronized across devices, if the user is signed into a Google Account on the Chrome instance and synchronization is enabled.
Disconnect the IdP from the RP
If a user has previously signed into the RP using the IdP through FedCM, the relationship is memorized by the browser locally as the list of connected accounts. The RP may initiate a disconnection by invoking the IdentityCredential.disconnect()
function. This function can be called from a top-level RP frame. The RP needs to pass a configURL
, the clientId
it uses under the IdP, and an accountHint
for the IdP to be disconnected. An account hint can be an arbitrary string as long as the disconnect endpoint can identify the account, for example an email address or user ID which does not necessarily match the account ID that the account list endpoint has provided:
// Disconnect an IdP account "account456" from the RP "https://idp.com/". This is invoked on the RP domain.
IdentityCredential.disconnect({
configURL: "https://idp.com/config.json",
clientId: "rp123",
accountHint: "account456"
});
IdentityCredential.disconnect()
returns a Promise
. This promise may throw an exception for the following reasons:
- The user hasn't signed in to the RP using the IdP through FedCM.
- The API is invoked from within an iframe without FedCM permissions policy.
- The configURL is invalid or missing the disconnect endpoint.
- Content Security Policy (CSP) check fails.
- There is a pending disconnect request.
- The user has disabled FedCM in the browser settings.
When the IdP's disconnect endpoint returns a response , the RP and the IdP are disconnected on the browser and the promise is resolved. The ID of the disconnected accounts are specified in the response from the disconnect endpoint .
Call FedCM from within a cross-origin iframe
FedCM can be invoked from within a cross-origin iframe using an identity-credentials-get
permissions policy, if the parent frame allows it. To do so, append the allow="identity-credentials-get"
attribute to the iframe tag as follows:
<iframe src="https://fedcm-cross-origin-iframe.glitch.me" allow="identity-credentials-get"></iframe>
You can see it in action in an example .
Optionally, if the parent frame wants to restrict the origins to call FedCM, send a Permissions-Policy
header with a list of allowed origins.
Permissions-Policy: identity-credentials-get=(self "https://fedcm-cross-origin-iframe.glitch.me")
You can learn more about how the Permissions Policy works at Controlling browser features with Permissions Policy .
,Learn how to use FedCM for privacy-preserving identity federation.
FedCM (Federated Credential Management) is a privacy-preserving approach to federated identity services (such as "Sign in with...") where users can log into sites without sharing their personal information with the identity service or the site.
To learn more about FedCM use cases, user flows, and API roadmap check out the introduction to FedCM API .
FedCM development environment
You need a secure context (HTTPS or localhost) both on the IdP and RP in Chrome to use the FedCM.
Debug code on Chrome on Android
Set up and run a server locally to debug your FedCM code. You can access this server in Chrome on an Android device connected using a USB cable with port forwarding.
You can use DevTools on desktop to debug Chrome on Android by following the instructions at Remote debug Android devices .
Block third-party cookies on Chrome
You can test how FedCM works without third-party cookies on Chrome before it's actually enforced.
To block third-party cookies, use Incognito mode , or choose "Block third-party cookies" in your desktop settings at chrome://settings/cookies
or on mobile by navigating to Settings > Site settings > Cookies .
Use the FedCM API
You integrate with FedCM by creating a well-known file , config file and endpoints for accounts list , assertion issuance and optionally client metadata .
From there, FedCM exposes JavaScript APIs that RPs can use to sign in with the IdP.
Create a well-known file
To prevent trackers from abusing the API , a well-known file must be served from /.well-known/web-identity
of eTLD+1 of the IdP.
For example, if the IdP endpoints are served under https://accounts.idp.example/
, they must serve a well-known file at https://idp.example/.well-known/web-identity
as well as an IdP config file . Here's an example well-known file content:
{
"provider_urls": ["https://accounts.idp.example/config.json"]
}
The JSON file must contain the provider_urls
property with an array of IdP config file URLs that can be specified as a path part of configURL
in navigator.credentials.get
by RPs . The number of URL strings in the array is limited to one, but this may change with your feedback in the future.
Create an IdP config file and endpoints
The IdP config file provides a list of required endpoints for the browser. IdPs will host this config file and the required endpoints and URLs. All JSON responses must be served with application/json
content-type.
The config file's URL is determined by the values provided to the navigator.credentials.get
call executed on an RP .
const credential = await navigator.credentials.get({
identity: {
context: 'signup',
providers: [{
configURL: 'https://accounts.idp.example/config.json',
clientId: '********',
nonce: '******'
}]
}
});
const { token } = credential;
Specify a full URL of the IdP config file location as a configURL
. When navigator.credentials.get()
is called on the RP, the browser fetches the config file with a GET
request without the Origin
header or the Referer
header. The request doesn't have cookies and doesn't follow redirects. This effectively prevents the IdP from learning who made the request and which RP is attempting to connect. Например:
GET /config.json HTTP/1.1
Host: accounts.idp.example
Accept: application/json
Sec-Fetch-Dest: webidentity
The browser expects a JSON response from the IdP which includes the following properties:
Свойство | Описание |
---|---|
accounts_endpoint (required) | URL for the accounts endpoint . |
client_metadata_endpoint (optional) | URL for the client metadata endpoint . |
id_assertion_endpoint (required) | URL for the ID assertion endpoint . |
disconnect (optional) | URL for the disconnect endpoint . |
login_url (required) | The login page URL for the user to sign in to the IdP. |
branding (optional) | Object which contains various branding options. |
branding.background_color (optional) | Branding option which sets the background color of the "Continue as..." button. Use the relevant CSS syntax, namely hex-color , hsl() , rgb() , or named-color . |
branding.color (optional) | Branding option which sets the text color of the "Continue as..." button. Use the relevant CSS syntax, namely hex-color , hsl() , rgb() , or named-color . |
branding.icons (optional) | Branding option which sets the icon object, displayed in the sign-in dialog. The icon object is an array with two parameters:
|
RP could modify the string in the FedCM dialog UI using the identity.context
value for navigator.credentials.get()
to accommodate predefined authentication contexts. Optional property can be one of "signin"
(default), "signup"
, "use"
or "continue"
.
Here's an example response body from the IdP:
{
"accounts_endpoint": "/accounts.php",
"client_metadata_endpoint": "/client_metadata.php",
"id_assertion_endpoint": "/assertion.php",
"disconnect_endpoint": "/disconnect.php",
"login_url": "/login",
"branding": {
"background_color": "green",
"color": "#FFEEAA",
"icons": [{
"url": "https://idp.example/icon.ico",
"size": 25
}]
}
}
Once the browser fetches the config file, it sends subsequent requests to the IdP endpoints:
Accounts endpoint
The IdP's accounts endpoint returns a list of accounts that the user is signed in on the IdP. If the IdP supports multiple accounts, this endpoint will return all signed in accounts.
The browser sends a GET
request with cookies with SameSite=None
, but without a client_id
parameter, the Origin
header or the Referer
header. This effectively prevents the IdP from learning which RP the user is trying to sign in to. Например:
GET /accounts.php HTTP/1.1
Host: accounts.idp.example
Accept: application/json
Cookie: 0x23223
Sec-Fetch-Dest: webidentity
Upon receiving the request, the server should:
- Verify that the request contains a
Sec-Fetch-Dest: webidentity
HTTP header. - Match the session cookies with the IDs of the already signed-in accounts.
- Respond with the list of accounts.
The browser expects a JSON response that includes an accounts
property with an array of account information with following properties:
Свойство | Описание |
---|---|
id (required) | Unique ID of the user. |
name (required) | Given and family name of the user. |
email (required) | Email address of the user. |
given_name (optional) | Given name of the user. |
picture (optional) | URL of the user avatar image. |
approved_clients (optional) | An array of RP client IDs which the user has registered with. |
login_hints (optional) | An array of all possible filter types that the IdP supports to specify an account. The RP can invoke navigator.credentials.get() with the loginHint property to selectively show the specified account. |
domain_hints (optional) | An array of all the domains the account is associated with. The RP can call navigator.credentials.get() with a domainHint property to filter the accounts. |
Example response body:
{
"accounts": [{
"id": "1234",
"given_name": "John",
"name": "John Doe",
"email": "john_doe@idp.example",
"picture": "https://idp.example/profile/123",
"approved_clients": ["123", "456", "789"],
"login_hints": ["demo1", "demo1@idp.example"]
}, {
"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", "demo2@idp.example"],
"domain_hints": ["corp.example"]
}]
}
If the user is not signed in, respond with HTTP 401 (Unauthorized).
The returned accounts list is consumed by the browser and won't be available to the RP.
Client metadata endpoint
The IdP's client metadata endpoint returns the relying party's metadata such as the RP's privacy policy and terms of service. RPs should provide links to their privacy policy and terms of service to the IdP in advance. These links are displayed in the sign-in dialog when the user hasn't registered on the RP with the IdP yet.
The browser sends a GET
request using the client_id
navigator.credentials.get
without cookies. Например:
GET /client_metadata.php?client_id=1234 HTTP/1.1
Host: accounts.idp.example
Origin: https://rp.example/
Accept: application/json
Sec-Fetch-Dest: webidentity
Upon receiving the request, the server should:
- Determine the RP for the
client_id
. - Respond with the client metadata.
The properties for the client metadata endpoint include:
Свойство | Описание |
---|---|
privacy_policy_url (optional) | RP privacy policy URL. |
terms_of_service_url (optional) | RP terms of service URL. |
The browser expects a JSON response from the endpoint:
{
"privacy_policy_url": "https://rp.example/privacy_policy.html",
"terms_of_service_url": "https://rp.example/terms_of_service.html",
}
The returned client metadata is consumed by the browser and won't be available to the RP.
ID assertion endpoint
The IdP's ID assertion endpoint returns an assertion for their signed-in user. When the user signs in to an RP website using navigator.credentials.get()
call , the browser sends a POST
request with cookies with SameSite=None
and a content-type of application/x-www-form-urlencoded
to this endpoint with the following information:
Свойство | Описание |
---|---|
client_id (required) | The RP's client identifier. |
account_id (required) | The unique ID of the signing in user. |
nonce (optional) | The request nonce, provided by the RP. |
disclosure_text_shown | Results in a string of "true" or "false" (rather than a boolean). The result is "false" if the disclosure text was not shown. This happens when the RP's client ID was included in the approved_clients property list of the response from the accounts endpoint or if the browser has observed a sign-up moment in the past in the absence of approved_clients . |
is_auto_selected | If auto-reauthentication is performed on the RP, is_auto_selected indicates "true" . Otherwise "false" . This is helpful to support more security related features. For example, some users may prefer a higher security tier which requires explicit user mediation in authentication. If an IdP receives a token request without such mediation, they could handle the request differently. For example, return an error code such that the RP can call the FedCM API again with mediation: required . |
Example HTTP header:
POST /assertion.php HTTP/1.1
Host: accounts.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=Ct60bD&disclosure_text_shown=true&is_auto_selected=true
Upon receiving the request, the server should:
- Respond to the request with CORS (Cross-Origin Resource Sharing) .
- Verify that the request contains a
Sec-Fetch-Dest: webidentity
HTTP header. - Match the
Origin
header against the RP origin determine by theclient_id
. Reject if they don't match. - Match
account_id
against the ID of the already signed-in account. Reject if they don't match. - Respond with a token. If the request is rejected, respond with an error response .
How the token is issued is up to the IdP, but in general, it's signed with information such as the account ID, client ID, issuer origin, nonce
, so that the RP can verify the token is genuine.
The browser expects a JSON response that includes the following property:
Свойство | Описание |
---|---|
token (required) | A token is a string that contains claims about the authentication. |
{
"token": "***********"
}
The returned token is passed to the RP by the browser, so that the RP can validate the authentication.
Return an error response
The id_assertion_endpoint
can also return an "error" response, which has two optional fields:
-
code
: The IdP can choose one of the known errors from the OAuth 2.0 specified error list (invalid_request
,unauthorized_client
,access_denied
,server_error
andtemporarily_unavailable
) or use any arbitrary string. If the latter, Chrome renders the error UI with a generic error message and pass the code to the RP. -
url
: It identifies a human-readable web page with information about the error to provide additional information about the error to users. This field is useful to users because browsers cannot provide rich error messages in a built-in UI. For example: links for next steps, or customer service contact information. If a user wants to learn more about the error details and how to fix it, they could visit the provided page from the browser UI for more details. The URL must be of the same-site as the IdPconfigURL
.
// id_assertion_endpoint response
{
"error" : {
"code": "access_denied",
"url" : "https://idp.example/error?type=access_denied"
}
}
Disconnect endpoint
By invoking IdentityCredential.disconnect()
, the browser sends a cross-origin POST
request with cookies with SameSite=None
and a content-type of application/x-www-form-urlencoded
to this disconnect endpoint with the following information:
Свойство | Описание |
---|---|
account_hint | A hint for the IdP account.. |
client_id | The RP's client identifier. |
POST /disconnect.php 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
Upon receiving the request, the server should:
- Respond to the request with CORS (Cross-Origin Resource Sharing) .
- Verify that the request contains a
Sec-Fetch-Dest: webidentity
HTTP header. - Match the
Origin
header against the RP origin determine by theclient_id
. Reject if they don't match. - Match
account_hint
against the IDs of the already signed-in accounts. - Disconnect the user account from the RP.
- Respond to the browser with the identified user account information in a JSON format.
An example response JSON payload looks like this:
{
"account_id": "account456"
}
Instead, if the IdP wishes the browser to disconnect all accounts associated with the RP, pass a string that does not match any account ID, for example "*"
.
Login URL
With the Login Status API , the IdP must inform the user's login status to the browser. However, the status could be out of sync, such as when the session expires . In such a scenario, the browser can dynamically let the user sign in to the IdP through the login page URL specified with the idp config file 's login_url
.
The FedCM dialog displays a message suggesting a sign in, as shown in the following image.
When the user clicks the Continue button, the browser opens a popup window for the IdP's login page.
The dialog is a regular browser window that has first-party cookies. Whatever happens within the dialog is up to the IdP, and no window handles are available to make a cross-origin communication request to the RP page. After the user is signed in, the IdP should:
- Send the
Set-Login: logged-in
header or call thenavigator.login.setStatus("logged-in")
API to inform the browser that the user has been signed in. - Call
IdentityProvider.close()
to close the dialog.
Inform the browser about the user's login status on the identity provider
The Login Status API is a mechanism where a website, especially an IdP, informs the browser the user's login status on the IdP. With this API, the browser can reduce unnecessary requests to the IdP and mitigate potential timing attacks.
IdPs can signal the user's login status to the browser by sending an HTTP header or by calling a JavaScript API when the user is signed in on the IdP or when the user is signed out from all their IdP accounts. For each IdP (identified by its config URL) the browser keeps a tri-state variable representing the login state with possible values logged-in
, logged-out
, and unknown
. The default state is unknown
.
To signal that the user is signed in, send an Set-Login: logged-in
HTTP header in a top-level navigation or a same-site subresource request at the IdP origin:
Set-Login: logged-in
Alternatively, call the JavaScript API navigator.login.setStatus("logged-in")
from the IdP origin in a top-level navigation:
navigator.login.setStatus("logged-in")
These calls record the user's login status as logged-in
. When the user's login status is set to logged-in
, the RP calling FedCM makes requests to the IdP's accounts endpoint and displays available accounts to the user in the FedCM dialog.
To signal that the user is signed out from all their accounts, send Set-Login: logged-out
HTTP header in a top-level navigation or a same-site subresource request at the IdP origin:
Set-Login: logged-out
Alternatively, call the JavaScript API navigator.login.setStatus("logged-out")
from the IdP origin in a top-level navigation:
navigator.login.setStatus("logged-out")
These calls record the user's login status as logged-out
. When the user's login status is logged-out
, calling the FedCM silently fails without making a request to the IdP's accounts endpoint.
The unknown
status is set before the IdP sends a signal using the Login Status API. Unknown
was introduced for a better transition, because a user may have already signed into the IdP when this API was shipped. The IdP may not have a chance to signal this to the browser by the time FedCM is first invoked. In this case, Chrome makes a request to the IdP's accounts endpoint and update the status based on the response from the accounts endpoint:
- If the endpoint returns a list of active accounts, update the status to
logged-in
and open the FedCM dialog to show those accounts. - If the endpoint returns no accounts, update the status to
logged-out
and fail the FedCM call.
Let the user sign in through a dynamic login flow
Even though the IdP keeps informing the user's login status to the browser, it could be out of sync, such as when the session expires. The browser tries to send a credentialed request to the accounts endpoint when the login status is logged-in
, but the server returns no accounts because the session is no longer available. In such a scenario, the browser can dynamically let the user sign in to the IdP through a popup window .
Sign in to the relying party with the identity provider
Once the IdP's configuration and endpoints are available, RPs can call navigator.credentials.get()
to request allowing users to sign in to the RP with the IdP.
Before calling the API, you need to confirm that FedCM is available on the user's browser . To check if FedCM is available, wrap this code around your FedCM implementation:
if ('IdentityCredential' in window) {
// If the feature is available, take action
}
To request allowing users to sign in to the IdP from the RP, do the following, for example:
const credential = await navigator.credentials.get({
identity: {
providers: [{
configURL: 'https://accounts.idp.example/config.json',
clientId: '********',
nonce: '******'
}]
}
});
const { token } = credential;
The providers
property takes an array of IdentityProvider
objects that have the following properties:
Свойство | Описание |
---|---|
configURL (required) | A full path of the IdP config file. |
clientId (required) | The RP's client identifier, issued by the IdP. |
nonce (optional) | A random string to ensure the response is issued for this specific request. Prevents replay attacks. |
loginHint (optional) | By specifying one of login_hints values provided by the accounts endpoints , the FedCM dialog selectively shows the specified account. |
domainHint (optional) | By specifying one of domain_hints values provided by the accounts endpoints , the FedCM dialog selectively show the specified account. |
The browser handles sign-up and sign-in use cases differently depending on the existence of approved_clients
in the response from the accounts list endpoint . The browser won't display a disclosure text "To continue with ...." if the user has already signed up to the RP.
The sign-up state is determined based on whether the following conditions are fulfilled or not:
- If
approved_clients
includes the RP'sclientId
. - If the browser remembers that the user has already signed up to the RP.
When the RP calls navigator.credentials.get()
, the following activities take place:
- The browser sends requests and fetches several documents:
- The well-known file and an IdP config file which declare endpoints.
- An accounts list .
- Optional: URLs for the RP's privacy policy and terms of service, retrieved from the client metadata endpoint .
- The browser displays the list of accounts that the user can use to sign-in, as well as the terms of service and privacy policy if available.
- Once the user chooses an account to sign in with, a request to the ID assertion endpoint is sent to the IdP to retrieve a token.
- The RP can validate the token to authenticate the user.
RPs are expected to support browsers which don't support FedCM, therefore users should be able to use an existing, non-FedCM sign-in process. Until third-party cookies are no longer available in browsers, this should remain non-problematic.
Once the token is validated by the RP server, the RP may register the user or let them sign-in and start a new session.
Login Hint API
After the user signs in, sometimes the relying party (RP) asks the user to reauthenticate. But the user may not be sure which account they've been using. If the RP can specify which account to sign in with, it would be easier for the user to pick an account.
RPs can selectively show a specific account by invoking navigator.credentials.get()
with the loginHint
property with one of login_hints
values fetched from the accounts list endpoint , as shown in the following code sample:
return await navigator.credentials.get({
identity: {
providers: [{
configURL: "https://idp.example/manifest.json",
clientId: "123",
nonce: nonce,
loginHint : "demo1@example.com"
}]
}
});
When no accounts match the loginHint
, the FedCM dialog shows a login prompt, which allows the user to login to an IdP account matching the hint requested by the RP. When the user taps on the prompt, a popup window is opened with the login URL specified in the config file . The link is then appended with the login hint and the domain hint query parameters.
Domain Hint API
There are cases where the RP already knows that only accounts associated with a certain domain are allowed to login to the site. This is particularly common in enterprise scenarios where the site being accessed is restricted to a corporate domain. To provide a better user experience, the FedCM API allows the RP to only show the accounts which may be used to login to the RP. This prevents scenarios where a user tries to login to the RP using an account outside of the corporate domain, only to be served with an error message later (or silence where the login did not work) because the right type of account was not used.
RPs can selectively show only matching accounts by invoking navigator.credentials.get()
with the domainHint
property with one of domain_hints
values fetched from the accounts list endpoint , as shown in the following code sample:
return await navigator.credentials.get({
identity: {
providers: [{
configURL: "https://idp.example/manifest.json",
clientId: "abc",
nonce: nonce,
domainHint : "corp.example"
}]
}
});
When no accounts match the domainHint
, the FedCM dialog shows a login prompt, which allows the user to login to an IdP account matching the hint requested by the RP. When the user taps on the prompt, a popup window is opened with the login URL specified in the config file . The link is then appended with the login hint and the domain hint query parameters.
Show an error message
Sometimes, the IdP may not be able to issue a token for legitimate reasons, such as when the client is unauthorized, the server is temporarily unavailable. If the IdP returns an "error" response, the RP can catch it, as well as Chrome notifies the user by showing a browser UI with the error information provided by the IdP.
try {
const cred = await navigator.credentials.get({
identity: {
providers: [
{
configURL: "https://idp.example/manifest.json",
clientId: "1234",
},
],
}
});
} catch (e) {
const code = e.code;
const url = e.url;
}
Auto-reauthenticate users after the initial authentication
FedCM auto-reauthentication ("auto-reauthn" in short) can let users reauthenticate automatically, when they come back after their initial authentication using FedCM. "The initial authentication" here means the user creates an account or signs into the RP's website by tapping on the "Continue as..." button on FedCM's sign-in dialog for the first time on the same browser instance.
While the explicit user experience makes sense before the user has created the federated account to prevent tracking (which is one of the main goals of FedCM), it is unnecessarily cumbersome after the user has gone through it once: after the user grants permission to allow communication between the RP and the IdP, there's no privacy or security benefit for enforcing another explicit user confirmation for something that they have already previously acknowledged.
With auto-reauthn, the browser changes its behavior depending on the option you specify for the mediation
when calling navigator.credentials.get()
.
const cred = await navigator.credentials.get({
identity: {
providers: [{
configURL: "https://idp.example/fedcm.json",
clientId: "1234",
}],
},
mediation: 'optional', // this is the default
});
// `isAutoSelected` is `true` if auto-reauthn was performed.
const isAutoSelected = cred.isAutoSelected;
The mediation
is a property in the Credential Management API , it behaves in the same way as it does for PasswordCredential and FederatedCredential and it's partially supported by PublicKeyCredential as well. The property accepts the following four values:
-
'optional'
(default): Auto-reauthn if possible, requires a mediation if not. We recommend choosing this option on the sign-in page. -
'required'
: Always requires a mediation to proceed, for example, clicking the "Continue" button on the UI. Choose this option if your users are expected to grant permission explicitly every time they need to be authenticated. -
'silent'
: Auto-reauthn if possible, silently fail without requiring a mediation if not. We recommend choosing this option on the pages other than the dedicated sign-in page but where you want to keep users signed in—for example, an item page on a shipping website or an article page on a news website. -
'conditional'
: Used for WebAuthn and not available for FedCM at the moment.
With this call, auto-reauthn happens under the following conditions:
- FedCM is available to use. For example, the user has not disabled FedCM either globally or for the RP in the settings.
- The user used only one account with FedCM API to sign into the website on this browser.
- The user is signed into the IdP with that account.
- The auto-reauthn didn't happen within the last 10 minutes.
- The RP hasn't called
navigator.credentials.preventSilentAccess()
after the previous sign in.
When these conditions are met, an attempt to automatically reauthenticate the user starts as soon as the FedCM navigator.credentials.get()
is invoked.
When mediation: optional
, auto-reauthn may be unavailable due to reasons that only the browser knows; the RP can check whether auto-reauthn is performed by examining the isAutoSelected
property.
This is helpful to evaluate the API performance and improve UX accordingly. Also, when it's unavailable, the user may be prompted to sign in with explicit user mediation, which is a flow with mediation: required
.
Enforce mediation with preventSilentAccess()
Auto-reauthenticating users immediately after they sign out wouldn't make for a very good user experience. That's why FedCM has a 10-minute quiet period after an auto-reauthn to prevent this behavior. This means that auto-reauthn happens at most once in every 10-minutes unless the user signs back in within 10-minutes. The RP should call navigator.credentials.preventSilentAccess()
to explicitly request the browser to disable auto-reauthn when a user signs out of the RP explicitly, for example, by clicking a sign-out button.
function signout() {
navigator.credentials.preventSilentAccess();
location.href = '/signout';
}
Users can opt-out of auto-reauthn in settings
Users can opt-out from auto-reauth from the settings menu:
- On desktop Chrome, go to
chrome://password-manager/settings
> Sign in automatically. - On Android Chrome, open Settings > Password Manager > Tap on a cog at the top right corner > Auto sign-in.
By disabling the toggle, the user can opt-out from auto-reauthn behavior all together. This setting is stored and synchronized across devices, if the user is signed into a Google Account on the Chrome instance and synchronization is enabled.
Disconnect the IdP from the RP
If a user has previously signed into the RP using the IdP through FedCM, the relationship is memorized by the browser locally as the list of connected accounts. The RP may initiate a disconnection by invoking the IdentityCredential.disconnect()
function. This function can be called from a top-level RP frame. The RP needs to pass a configURL
, the clientId
it uses under the IdP, and an accountHint
for the IdP to be disconnected. An account hint can be an arbitrary string as long as the disconnect endpoint can identify the account, for example an email address or user ID which does not necessarily match the account ID that the account list endpoint has provided:
// Disconnect an IdP account "account456" from the RP "https://idp.com/". This is invoked on the RP domain.
IdentityCredential.disconnect({
configURL: "https://idp.com/config.json",
clientId: "rp123",
accountHint: "account456"
});
IdentityCredential.disconnect()
returns a Promise
. This promise may throw an exception for the following reasons:
- The user hasn't signed in to the RP using the IdP through FedCM.
- The API is invoked from within an iframe without FedCM permissions policy.
- The configURL is invalid or missing the disconnect endpoint.
- Content Security Policy (CSP) check fails.
- There is a pending disconnect request.
- The user has disabled FedCM in the browser settings.
When the IdP's disconnect endpoint returns a response , the RP and the IdP are disconnected on the browser and the promise is resolved. The ID of the disconnected accounts are specified in the response from the disconnect endpoint .
Call FedCM from within a cross-origin iframe
FedCM can be invoked from within a cross-origin iframe using an identity-credentials-get
permissions policy, if the parent frame allows it. To do so, append the allow="identity-credentials-get"
attribute to the iframe tag as follows:
<iframe src="https://fedcm-cross-origin-iframe.glitch.me" allow="identity-credentials-get"></iframe>
You can see it in action in an example .
Optionally, if the parent frame wants to restrict the origins to call FedCM, send a Permissions-Policy
header with a list of allowed origins.
Permissions-Policy: identity-credentials-get=(self "https://fedcm-cross-origin-iframe.glitch.me")
You can learn more about how the Permissions Policy works at Controlling browser features with Permissions Policy .