在信赖方端使用 FedCM 实现身份解决方案

依赖方 (RP) 需要完成以下步骤才能在其网站上启用 FedCM

IdP 的配置和端点可用后,RP 可以调用 navigator.credentials.get() 来请求允许用户使用 IdP 登录 RP。

在调用该 API 之前,您需要确认 FedCM 是否可在用户的浏览器中使用。如需检查 FedCM 是否可用,请在 FedCM 实现中封装以下代码:

  if ('IdentityCredential' in window) {
    // If the feature is available, take action
  } else {
    // FedCM is not supported, use a different identity solution
  }

如需允许用户使用 FedCM 在 RP 上登录 IdP,RP 可以调用 navigator.credentials.get(),例如:

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

情境属性

借助可选的 context 属性,RP 可以修改 FedCM 对话框界面中的字符串(例如“登录 rp.example…”、“使用 idp.example…”),以适应预定义的身份验证上下文。context 属性可以具有以下值:

  • signin(默认)
  • signup
  • use
一张图表,说明了 FedCM 对话框的界面组件:左上角显示了一个图标。该图标右侧是显示“使用 IdP 登录 RP”消息的上下文组件。底部是带有自定义文本和背景颜色的“Continue”(继续)按钮。
如何将品牌信息应用于 FedCM 对话框

例如,将 context 设置为 use 会导致以下消息:

显示自定义上下文消息的 FedCM 对话框:上下文消息显示“使用”FedCM,而不是“登录”FedCM。
显示自定义情境消息的 FedCM 对话框。

浏览器会根据 accounts list 端点响应中是否存在 approved_clients 来不同地处理注册和登录用例。如果用户已注册 RP,浏览器将不会显示披露文本“如要继续使用...,请点击此处”
providers 属性接受一个 IdentityProvider 对象数组,该数组具有以下属性:

Providers 属性

providers 属性接受一个 IdentityProvider 对象数组,该数组具有以下属性:

属性 说明
configURL(必需) IdP 配置文件的完整路径。
clientId(必需) IdP 签发的 RP 客户端标识符。
loginHint(可选) 通过指定 accounts 端点提供的 login_hints 值之一,FedCM 对话框会选择性地显示指定的账号。
domainHint(可选) 通过指定 accounts 端点提供的 domain_hints 值之一,FedCM 对话框会选择性地显示指定的账号。
mode(可选) 用于指定 FedCM 的界面模式的字符串。可以是以下值之一:
  • "active":FedCM 提示必须由用户互动(例如点击按钮)触发。
  • "passive":FedCM 提示将在不直接与用户互动的情况下发起。
如需详细了解主动模式和被动模式之间的区别,请参阅概览页面

注意:Chrome 132 开始支持 mode 参数。
fields(可选) 字符串数组,用于指定 RP 需要 IdP 与其分享的用户信息(“name”“email”“picture”)。
注意:Chrome 132 及更高版本支持 Field API。
params(可选) 允许指定其他键值对参数的自定义对象:
  • scope:一个字符串值,包含 RP 需要请求的其他权限,例如 "drive.readonly calendar.readonly"
  • nonce:一个随机字符串,用于确保系统针对此特定请求发出响应。防范重放攻击。
  • 其他自定义键值对参数。

注意:Chrome 132 开始支持 params

活动模式

FedCM 支持不同的用户体验模式配置。被动模式是默认模式,开发者无需对其进行配置。

如需在活动模式下使用 FedCM,请执行以下操作:

  1. 检查用户浏览器中功能的适用范围。
  2. 使用瞬时用户手势(例如按钮点击)调用 API。
  3. mode 参数传递给 API 调用:
  let supportsFedCmMode = false;
  try {
    navigator.credentials.get({
      identity: Object.defineProperty(
        // Check if this Chrome version supports the Mode API.
        {}, 'mode', {
          get: function () { supportsFedCmMode = true; }
        }
      )
    });
  } catch(e) {}

  if (supportsFedCmMode) {
    // The button mode is supported. Call the API with mode property:
    return await navigator.credentials.get({
      identity: {
        providers: [{
          configURL: 'https://idp.example/config.json',
          clientId: '123',
        }],
        // The 'mode' value defines the UX mode of FedCM.
        // - 'active': Must be initiated by user interaction (e.g., clicking a button).
        // - 'passive': Can be initiated without direct user interaction.
        mode: 'active'
      }
    });
  }

活动模式下的自定义图标

在活动模式下,IdP 可以直接在客户端元数据端点响应中添加 RP 的官方徽标图标。RP 必须提前提供其品牌数据。

从跨源 iframe 内调用 FedCM

您可以使用 identity-credentials-get 权限政策从跨源 iframe 中调用 FedCM(如果父级框架允许)。为此,请将 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")

如需详细了解权限政策的运作方式,请参阅使用权限政策控制浏览器功能

Login Hint API

使用登录提示,RP 可以建议用户应使用哪个账号登录。如果用户不确定自己之前使用的是哪个账号,此功能有助于重新验证其身份。

RP 可以通过将 loginHint 属性与从账号列表端点提取的 login_hints 值之一一起调用 navigator.credentials.get(),以选择性地显示特定账号,如以下代码示例所示:

  return await navigator.credentials.get({
    identity: {
      providers: [{
        configURL: 'https://idp.example/manifest.json',
        clientId: '123',
        // Accounts endpoint can specify a 'login_hints' array for an account.
        // When RP specifies a 'exampleHint' value, only those accounts will be
        // shown to the user whose 'login_hints' array contains the 'exampleHint'
        // value
        loginHint : 'exampleHint'
      }]
    }
  });

如果没有账号与 loginHint 匹配,FedCM 对话框会显示登录提示,以便用户登录与 RP 请求的提示相符的 IdP 账号。当用户点按提示时,系统会打开一个弹出式窗口,其中包含配置文件中指定的登录网址。然后,在链接后附加登录提示和网域提示查询参数。

Domain Hint API

RP 可以选择仅显示与特定网域关联的账号。对于仅限于公司网域的 RP,这可能会很有用。

如需仅显示特定网域账号,RP 应使用从账号列表端点提取的 domain_hints 值之一调用 navigator.credentials.get()domainHint 属性,如以下代码示例所示:

  return await navigator.credentials.get({
    identity: {
      providers: [{
        configURL: 'https://idp.example/manifest.json',
        clientId: 'abc',
        // Accounts endpoint can specify a 'domain_hints' array for an account.
        // When RP specifies a '@domain.example' value, only those accounts will be
        // shown to the user whose 'domain_hints' array contains the
        // '@domain.example' value
        domainHint : '@domain.example'
      }]
    }
  });

如果没有账号与 domainHint 匹配,FedCM 对话框会显示登录提示,以便用户登录与 RP 请求的提示匹配的 IdP 账号。当用户点按提示时,系统会打开一个弹出式窗口,其中包含配置文件中指定的登录网址。然后,在链接后附加登录提示和网域提示查询参数。

当没有账号与 domainHint 匹配时显示的登录提示示例。
当没有账号与 domainHint 匹配时显示的登录提示示例。

自定义参数

借助“自定义参数”功能,RP 可以向ID 断言端点提供其他键值对参数。借助 Parameters API,RP 可以向 IdP 传递额外的参数,以请求基本登录以外的资源权限。在以下情况下,传递其他参数会很有用:

  • RP 需要动态请求 IdP 拥有的其他权限,例如结算地址或日历访问权限。用户可以通过使用“继续操作”功能启动的 IdP 控制的用户体验流程授予这些权限,然后 IdP 会分享这些信息。

如需使用该 API,RP 会在 navigator.credentials.get() 调用中将参数作为对象添加到 params 属性:

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

浏览器会自动将其转换为向 IdP 发送的 POST 请求,其中参数为单个经过网址编码的 JSON 序列化对象:

  // The assertion endpoint is drawn from the config file
  POST /fedcm_assertion_endpoint HTTP/1.1
  Host: idp.example
  Origin: https://rp.example/
  Content-Type: application/x-www-form-urlencoded
  Cookie: 0x23223
  Sec-Fetch-Dest: webidentity

  // params are translated into urlencoded version of `{"IDP_SPECIFIC_PARAM":"1","foo":"bar"}`
  account_id=123&client_id=client1234&params=%22%7B%5C%22IDP_SPECIFIC_PARAM%5C%22%3A1%2C%5C%22foo%5C%22%3A%5C%22BAR%5C%22%7D%22.

如果 RP 需要任何其他权限,IdP 可以提供重定向链接。例如,在 node.js 中:

  if (rpRequestsPermissions) {
    // Response with a URL if the RP requests additional permissions
    return res.json({
      continue_on: '/example-redirect',
    });
  }

字段

RP 可以指定他们需要 IdP 与其共享的用户信息(姓名、电子邮件地址和个人资料照片的任意组合)。系统会在 FedCM 对话框的披露信息界面中显示所请求的信息。如果用户选择登录,系统会显示一条消息,告知用户 idp.example 会与 rp.example 共享所请求的信息。

显示披露信息消息的 FedCM 活跃模式对话框。如要继续,身份提供程序会与该网站分享用户的电子邮件地址和个人资料照片。
处于活动模式下的披露消息:RP 请求 IdP 仅分享用户电子邮件地址和个人资料照片。

如需使用“字段”功能,RP 应在 navigator.credentials.get() 调用中添加 fields 数组。这些字段可以包含 nameemailpicture 的任何排列组合。未来,此列表可能会扩展为包含更多值。包含 fields 的请求如下所示:

  let { token } = await navigator.credentials.get({
    identity: {
      providers: [{
        // RP requests the IdP to share only user email and profile picture
        fields: [ 'email', 'picture'],
        clientId: '1234',
        configURL: 'https://idp.example/fedcm.json',

      },
    }
  });

浏览器会自动将其转换为向ID 断言端点发出的 HTTP 请求,其中包含 RP 指定的 fields 参数,以及浏览器在 disclosure_shown_for 参数中向用户披露的字段。为了实现向后兼容,如果已显示披露文本,并且请求的字段包括 三个字段'name''email''picture',浏览器还会发送 disclosure_text_shown=true

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

  // The RP only requested to share email and picture. The browser will send `disclosure_text_shown=false`, as the 'name' field value is missing
  account_id=123&client_id=client1234&disclosure_text_shown=false&fields=email,picture&disclosure_shown_for=email,picture

如果 fields 是空数组,用户代理将跳过披露界面。

不显示披露信息界面消息的 FedCM 被动模式对话框。
在被动模式下,系统不会显示披露信息消息。在按钮流程中,系统会完全跳过披露声明界面。

即使 accounts 端点的响应不包含与 approved_clients 中的 RP 匹配的客户端 ID,也存在这种情况。

在这种情况下,发送到ID 断言端点disclosure_text_shown 在 HTTP 正文中为 false:

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

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

显示错误消息

有时,身份提供方可能出于合法原因而无法签发令牌,例如客户端未经授权或服务器暂时不可用。如果 IdP 返回“错误”响应,RP 可以捕获该响应,Chrome 可以通过显示包含 IdP 提供的错误信息的浏览器界面来通知用户。

A
FedCM 对话框,显示用户登录尝试失败后的错误消息。此字符串与错误类型相关联。
  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 自动重新身份验证(简称“auto-reauthn”)可让用户在使用 FedCM 进行初始身份验证后再次访问时自动重新进行身份验证。这里的“初始身份验证”是指用户在同一浏览器实例中首次点按 FedCM 登录对话框中的“Continue as...” 按钮,创建账号或登录 RP 的网站。

虽然在用户创建联合账号以防止跟踪(这是 FedCM 的主要目标之一)之前,明确的用户体验很有意义,但在用户完成一次体验后,再强制用户针对之前已确认的内容再次明确确认,就显得多余且繁琐:在用户授予允许 RP 与 IdP 之间通信的权限后,再强制用户针对之前已确认的内容再次明确确认,对隐私或安全没有任何好处。

使用自动重新授权时,浏览器会根据您在调用 navigator.credentials.get() 时为 mediation 指定的选项来更改其行为。

  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;

mediationCredential Management API 中的属性,其行为与 PasswordCredentialFederatedCredential 相同,并且 PublicKeyCredential 也对其提供部分支持。该属性接受以下四个值:

  • 'optional'(默认):尽可能自动重新授权,否则需要中介。我们建议您在登录页面上选择此选项。
  • 'required':始终需要中介才能继续,例如点击界面上的“继续”按钮。如果您希望用户每次需要进行身份验证时都明确授予权限,请选择此选项。
  • 'silent':如果可能,自动重新授权;如果不可能,则静默失败,无需中介。我们建议您在专用登录页面以外但希望用户保持登录状态的页面上选择此选项,例如配送网站上的商品页面或新闻网站上的文章页面。
  • 'conditional':用于 WebAuthn,目前不适用于 FedCM。

在进行此调用时,会在以下情况下自动重新授权:

  • FedCM 可供使用。例如,用户尚未在设置中全局停用 FedCM 或针对 RP 停用 FedCM。
  • 用户仅使用一个具有 FedCM API 的账号在此浏览器上登录了该网站。
  • 用户已使用该账号登录 IdP。
  • 自动重新授权未在过去 10 分钟内发生。
  • RP 在之前的登录之后未调用 navigator.credentials.preventSilentAccess()

满足这些条件后,系统会在调用 FedCM navigator.credentials.get() 后立即尝试自动重新对用户进行身份验证。

mediation: optional 时,由于只有浏览器知道的原因,自动重新授权可能不可用;RP 可以通过检查 isAutoSelected 属性来检查是否执行了自动重新授权。

这有助于评估 API 性能并相应地改进用户体验。 此外,当该功能不可用时,系统可能会提示用户通过显式用户中介进行登录,这是一种包含 mediation: required 的流程。

用户通过 FedCM 自动重新进行身份验证。

使用 preventSilentAccess() 强制执行中介

如果在用户退出账号后立即自动重新对其进行身份验证,用户体验会很差。因此,FedCM 在自动重新授权后会有一个 10 分钟的静默期,以防止出现这种行为。这意味着,除非用户在 10 分钟内重新登录,否则系统每 10 分钟最多会自动重新授权一次。当用户明确退出 RP(例如,点击“退出”按钮)时,RP 应调用 navigator.credentials.preventSilentAccess() 以明确请求浏览器停用自动重新授权。

  function signout() {
    navigator.credentials.preventSilentAccess();
    location.href = '/signout';
  }

用户可以在设置中选择停用自动重新授权

用户可以在“设置”菜单中选择停用自动重新授权:

  • 在桌面版 Chrome 中,依次选择 chrome://password-manager/settings > 自动登录。
  • 在 Android 版 Chrome 中,依次打开设置 > 密码管理工具 > 点按右上角的齿轮图标 >“自动登录”。

通过停用此切换开关,用户可以完全停用自动重新授权行为。如果用户在 Chrome 实例中登录了 Google 账号并启用了同步功能,系统会存储此设置并在设备间同步。

断开 IdP 与 RP 之间的连接

如果用户之前通过 FedCM 使用 IdP 登录了 RP,浏览器会在本地将该关系记忆为已关联账号的列表。RP 可以通过调用 IdentityCredential.disconnect() 函数来发起断开连接。此函数可从顶级 RP 帧调用。RP 需要传递 configURL(它在 IdP 下使用的 clientId)和 accountHint,以便断开 IdP 的连接。账号提示可以是任意字符串,只要断开连接端点可以识别账号即可,例如电子邮件地址或用户 ID,该 ID 不一定与账号列表端点提供的账号 ID 相匹配:

  // 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。此 promise 可能会因以下原因抛出异常:

  • 用户尚未通过 FedCM 使用 IdP 登录 RP。
  • 从不含 FedCM 权限政策的 iframe 中调用 API。
  • config网址 无效或缺少断开连接端点。
  • 内容安全政策 (CSP) 检查失败。
  • 有一个待处理的解除关联请求。
  • 用户已在浏览器设置中停用 FedCM。

身份提供方的断开连接端点返回响应时,浏览器上的 RP 和 IdP 会断开连接,并且 Promise 会解析。已解除关联的账号的 ID 在解除关联端点的响应中指定。

Next steps

Review how to implement your identity solution with FedCM on the Identity Provider side.
Explore how users and developers can manage FedCM participation, including opting in or out, across platforms and sites.