Triển khai giải pháp nhận dạng bằng FedCM

FedCM (Quản lý thông tin xác thực liên kết) là một phương pháp bảo vệ quyền riêng tư cho các dịch vụ danh tính liên kết (chẳng hạn như "Đăng nhập bằng...") cho phép người dùng đăng nhập vào các trang web mà không cần chia sẻ thông tin cá nhân của họ với dịch vụ danh tính hoặc trang web đó.

Việc triển khai FedCM bao gồm một số bước chính cho cả IdP (Nhà cung cấp danh tính) và RP (Bên phụ thuộc).

IdPs phải hoàn tất các bước sau để triển khai FedCM:

RP cần hoàn tất các bước sau để bật FedCM trên trang web của họ:

Triển khai FedCM làm IdP

Tìm hiểu thêm về các bước triển khai FedCM ở phía Nhà cung cấp dịch vụ nhận dạng (IdP).

Tạo tệp well-known

Để ngăn trình theo dõi lợi dụng API, bạn phải phân phát một tệp đã biết từ /.well-known/web-identity của eTLD+1 của IDP.

Tệp đã biết có thể bao gồm các thuộc tính sau:

Thuộc tính Bắt buộc Mô tả
provider_urls bắt buộc Mảng các đường dẫn tệp cấu hình IdP. Bỏ qua (nhưng vẫn bắt buộc) nếu bạn chỉ định accounts_endpointlogin_url.
accounts_endpoint nên dùng, yêu cầu login_url
URL cho điểm cuối tài khoản. Điều này cho phép hỗ trợ nhiều cấu hình, miễn là mỗi tệp cấu hình sử dụng cùng một URL login_urlaccounts_endpoint.

Lưu ý: Thông số này được hỗ trợ từ Chrome 132.
login_url nên dùng, yêu cầu accounts_endpoint URL trang đăng nhập để người dùng đăng nhập vào IdP. Điều này cho phép hỗ trợ nhiều cấu hình, miễn là mỗi tệp cấu hình sử dụng cùng một login_urlaccounts_endpoint.

Lưu ý: thông số này được hỗ trợ kể từ Chrome 132 trở lên.

Ví dụ: nếu các điểm cuối của IdP được phân phát trong https://accounts.idp.example/, thì các điểm cuối đó phải phân phát một tệp well-known tại https://idp.example/.well-known/web-identity cũng như tệp cấu hình IdP. Dưới đây là ví dụ về nội dung tệp phổ biến:

  {
    "provider_urls": ["https://accounts.idp.example/config.json"]
  }

Các IdP có thể chứa nhiều tệp cấu hình cho một IdP bằng cách chỉ định accounts_endpointlogin_url trong tệp well-known.
Tính năng này có thể hữu ích trong các trường hợp sau:

  • Một IdP cần hỗ trợ nhiều cấu hình thử nghiệm và cấu hình chính thức.
  • Nhà cung cấp danh tính cần hỗ trợ nhiều cấu hình theo khu vực (ví dụ: eu-idp.exampleus-idp.example).

Để hỗ trợ nhiều cấu hình (ví dụ: để phân biệt giữa môi trường thử nghiệm và môi trường sản xuất), IdP phải chỉ định accounts_endpointlogin_url:

  {
    // This property is required, but will be ignored when IdP supports
    // multiple configs (when `accounts_endpoint` and `login_url` are
    // specified), as long as `accounts_endpoint` and `login_url` in
    // that config file match those in the well-known file.
    "provider_urls": [ "https://idp.example/fedcm.json" ],

    // Specify accounts_endpoint and login_url properties to support
    // multiple config files.
    // Note: The accounts_endpoint and login_url must be identical
    // across all config files. Otherwise,
    // the configurations won't be supported.
    "accounts_endpoint": "https://idp.example/accounts",
    "login_url": "https://idp.example/login"
  }

Tạo tệp cấu hình IdP và điểm cuối

Tệp cấu hình IdP cung cấp danh sách các điểm cuối bắt buộc cho trình duyệt. IdP phải lưu trữ một hoặc nhiều tệp cấu hình, cũng như các điểm cuối và URL bắt buộc. Tất cả phản hồi JSON phải được phân phát bằng loại nội dung application/json.

URL của tệp cấu hình được xác định bằng các giá trị được cung cấp cho lệnh gọi navigator.credentials.get() được thực thi trên một RP.

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

RP sẽ chuyển URL của tệp cấu hình đến lệnh gọi API FedCM để cho phép người dùng đăng nhập:

  // Executed on RP's side:
  const credential = await navigator.credentials.get({
    identity: {
      context: 'signup',
      providers: [{
        // To allow users to sign in with an IdP using FedCM, RP specifies the IdP's config file URL:
        configURL: 'https://accounts.idp.example/fedcm.json',
        clientId: '********',
  });
  const { token } = credential;

Trình duyệt sẽ tìm nạp tệp cấu hình bằng yêu cầu GET mà không có tiêu đề Origin hoặc tiêu đề Referer. Yêu cầu không có cookie và không tuân theo lệnh chuyển hướng. Điều này giúp ngăn IdP biết được ai đã đưa ra yêu cầu và RP nào đang cố gắng kết nối. Ví dụ:

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

IdP phải triển khai một điểm cuối cấu hình phản hồi bằng JSON. Tệp JSON bao gồm các thuộc tính sau:

Thuộc tính Mô tả
accounts_endpoint (bắt buộc) URL cho điểm cuối tài khoản.
accounts.include (không bắt buộc) Chuỗi nhãn tài khoản tuỳ chỉnh, xác định những tài khoản sẽ được trả về khi sử dụng tệp cấu hình này, ví dụ: "accounts": {"include": "developer"}.
Nhà cung cấp danh tính có thể triển khai tính năng gắn nhãn tuỳ chỉnh cho tài khoản như sau:

Ví dụ: một IdP triển khai tệp cấu hình "https://idp.example/developer-config.json" với "accounts": {"include": "developer"} được chỉ định. IdP cũng đánh dấu một số tài khoản bằng nhãn "developer" bằng cách sử dụng tham số labels trong điểm cuối tài khoản. Khi một RP gọi navigator.credentials.get() với tệp cấu hình "https://idp.example/developer-config.json" được chỉ định, hệ thống sẽ chỉ trả về những tài khoản có nhãn "developer".
client_metadata_endpoint (không bắt buộc) URL cho điểm cuối siêu dữ liệu ứng dụng.
id_assertion_endpoint (bắt buộc) URL cho điểm cuối xác nhận mã nhận dạng.
disconnect (không bắt buộc) URL cho điểm cuối ngắt kết nối.
login_url (bắt buộc) URL trang đăng nhập để người dùng đăng nhập vào IdP.
branding (không bắt buộc) Đối tượng chứa nhiều tuỳ chọn thương hiệu.
branding.background_color (không bắt buộc) Tuỳ chọn xây dựng thương hiệu giúp đặt màu nền của nút "Tiếp tục dưới tư cách...". Sử dụng cú pháp CSS có liên quan, cụ thể là hex-color, hsl(), rgb() hoặc named-color.
branding.color (không bắt buộc) Tuỳ chọn xây dựng thương hiệu giúp đặt màu văn bản của nút "Tiếp tục dưới tư cách...". Sử dụng cú pháp CSS có liên quan, cụ thể là hex-color, hsl(), rgb() hoặc named-color.
branding.icons (không bắt buộc) Mảng các đối tượng biểu tượng. Các biểu tượng này xuất hiện trong hộp thoại đăng nhập. Đối tượng biểu tượng có hai tham số:
  • url (bắt buộc): URL của hình ảnh biểu tượng. Tính năng này không hỗ trợ hình ảnh SVG.
  • size (không bắt buộc): Kích thước biểu tượng, ứng dụng giả định là hình vuông và độ phân giải đơn. Số này phải lớn hơn hoặc bằng 25px ở chế độ thụ động và lớn hơn hoặc bằng 40px ở chế độ chủ động.
modes Đối tượng chứa thông số kỹ thuật về cách hiển thị giao diện người dùng FedCM ở các chế độ khác nhau:
  • active
  • passive
modes.active Đối tượng chứa các thuộc tính cho phép tuỳ chỉnh hành vi của FedCM ở một chế độ cụ thể. Cả modes.activemodes.passive đều có thể chứa tham số sau:
  • supports_use_other_account: boolean chỉ định xem người dùng có thể đăng nhập bằng một tài khoản khác với tài khoản mà họ đang đăng nhập hay không (nếu IdP hỗ trợ nhiều tài khoản).

Lưu ý: Tính năng Sử dụng tài khoản khác và chế độ đang hoạt động được hỗ trợ từ Chrome 132.
modes.passive

Dưới đây là ví dụ về nội dung phản hồi của IdP:

  {
    "accounts_endpoint": "/accounts.example",
    "client_metadata_endpoint": "/client_metadata.example",
    "id_assertion_endpoint": "/assertion.example",
    "disconnect_endpoint": "/disconnect.example",
    "login_url": "/login",
    // When RPs use this config file, only those accounts will be
    //returned that include `developer` label in the accounts endpoint.
    "accounts": {"include": "developer"},
    "modes": {
        "active": {
          "supports_use_other_account": true,
        }
    },
    "branding": {
      "background_color": "green",
      "color": "#FFEEAA",
      "icons": [{
        "url": "https://idp.example/icon.ico",
        "size": 25
      }]
    }
  }

Sau khi tìm nạp tệp cấu hình, trình duyệt sẽ gửi các yêu cầu tiếp theo đến điểm cuối của IdP:

Điểm cuối của IdP
Các điểm cuối của IdP

Sử dụng tài khoản khác

Người dùng có thể chuyển sang một tài khoản khác với tài khoản mà họ đang đăng nhập, nếu IdP hỗ trợ nhiều tài khoản hoặc thay thế tài khoản hiện có.

Để cho phép người dùng chọn các tài khoản khác, IdP phải chỉ định tính năng này trong tệp cấu hình:

  {
    "accounts_endpoint" : "/accounts.example",
    "modes": {
      "active": {
        // Allow the user to choose other account (false by default)
        "supports_use_other_account": true
      }
      // "passive" mode can be configured separately
    }
  }

Điểm cuối tài khoản

Điểm cuối tài khoản của IdP trả về danh sách tài khoản mà người dùng đã đăng nhập trên IdP. Nếu IdP hỗ trợ nhiều tài khoản, thì điểm cuối này sẽ trả về tất cả tài khoản đã đăng nhập.

Trình duyệt gửi một yêu cầu GET có cookie với SameSite=None, nhưng không có tham số client_id, tiêu đề Origin hoặc tiêu đề Referer. Điều này giúp ngăn IdP tìm hiểu được RP mà người dùng đang cố gắng đăng nhập. Ví dụ:

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

Sau khi nhận được yêu cầu, máy chủ phải:

  1. Xác minh rằng yêu cầu chứa tiêu đề HTTP Sec-Fetch-Dest: webidentity.
  2. So khớp cookie phiên với mã nhận dạng của các tài khoản đã đăng nhập.
  3. Phản hồi bằng danh sách tài khoản.

Trình duyệt sẽ mong đợi một phản hồi JSON bao gồm một thuộc tính accounts với một mảng thông tin tài khoản có các thuộc tính sau:

Thuộc tính Mô tả
id (bắt buộc) Mã nhận dạng duy nhất của người dùng.
name (bắt buộc) Họ và tên của người dùng.
email (bắt buộc) Địa chỉ email của người dùng.
given_name (không bắt buộc) Tên của người dùng.
picture (không bắt buộc) URL của hình đại diện của người dùng.
approved_clients (không bắt buộc) Một mảng gồm các mã ứng dụng RP mà người dùng đã đăng ký.
login_hints (không bắt buộc) Một mảng gồm tất cả các loại bộ lọc có thể có mà IdP hỗ trợ để chỉ định một tài khoản. RP có thể gọi navigator.credentials.get() bằng thuộc tính loginHint để hiển thị có chọn lọc tài khoản đã chỉ định.
domain_hints (không bắt buộc) Một mảng gồm tất cả các miền mà tài khoản được liên kết. RP có thể gọi navigator.credentials.get() bằng thuộc tính domainHint để lọc tài khoản.
labels (không bắt buộc) Mảng chuỗi Nhãn tài khoản tuỳ chỉnh mà một tài khoản được liên kết.
IdP có thể triển khai tính năng gắn nhãn tuỳ chỉnh cho tài khoản như sau:
  • Chỉ định nhãn tài khoản trong điểm cuối tài khoản (bằng cách sử dụng tham số labels này).
  • Tạo tệp cấu hình cho từng nhãn cụ thể.

Ví dụ: một IdP triển khai tệp cấu hình https://idp.example/developer-config.json với "accounts": {"include": "developer"} được chỉ định. IdP cũng đánh dấu một số tài khoản bằng nhãn "developer" bằng cách sử dụng tham số labels trong điểm cuối tài khoản. Khi một RP gọi navigator.credentials.get() với tệp cấu hình https://idp.example/developer-config.json được chỉ định, hệ thống sẽ chỉ trả về những tài khoản có nhãn "developer".

Nhãn tài khoản tuỳ chỉnh khác với gợi ý đăng nhập và gợi ý miền ở chỗ các nhãn này do máy chủ IdP duy trì hoàn toàn và RP chỉ chỉ định tệp cấu hình cần sử dụng.

Ví dụ về nội dung phản hồi:

  {
    "accounts": [{
      "id": "1234",
      "given_name": "John",
      "name": "John Doe",
      "email": "john_doe@idp.example",
      "picture": "https://idp.example/profile/123",
      // Ids of those RPs where this account can be used
      "approved_clients": ["123", "456", "789"],
      // This account has 'login_hints`. When an RP calls `navigator.credentials.get()`
      // with a `loginHint` value specified, for example, `exampleHint`, only those
      // accounts will be shown to the user whose 'login_hints' array contains the `exampleHint`.
      "login_hints": ["demo1", "exampleHint"],
      // This account is labelled. IdP can implement a specific config file for a
      // label, for example, `https://idp.example/developer-config.json`. Like that
      // RPs can filter out accounts by calling `navigator.credentials.get()` with
      // `https://idp.example/developer-config.json` config file.
      "labels": ["hr", "developer"]
    }, {
      "id": "5678",
      "given_name": "Johnny",
      "name": "Johnny",
      "email": "johnny@idp.example",
      "picture": "https://idp.example/profile/456",
      "approved_clients": ["abc", "def", "ghi"],
      "login_hints": ["demo2"],
      "domain_hints": ["@domain.example"]
    }]
  }

Nếu người dùng chưa đăng nhập, hãy phản hồi bằng HTTP 401 (Không được phép).

Danh sách tài khoản được trả về sẽ do trình duyệt sử dụng và sẽ không có sẵn cho RP.

Điểm cuối xác nhận giấy tờ tuỳ thân

Điểm cuối xác nhận danh tính của IdP trả về một xác nhận cho người dùng đã đăng nhập. Khi người dùng đăng nhập vào trang web RP bằng lệnh gọi navigator.credentials.get(), trình duyệt sẽ gửi một yêu cầu POST có cookie với SameSite=None và loại nội dung là application/x-www-form-urlencoded đến điểm cuối này với thông tin sau:

Thuộc tính Mô tả
client_id (bắt buộc) Giá trị nhận dạng ứng dụng của RP.
account_id (bắt buộc) Mã nhận dạng duy nhất của người dùng đăng nhập.
disclosure_text_shown Kết quả là một chuỗi "true" hoặc "false" (thay vì một boolean). Kết quả là "false" trong các trường hợp sau:
  • Nếu văn bản thông tin công bố không xuất hiện vì mã ứng dụng của RP có trong danh sách thuộc tính approved_clients của phản hồi từ điểm cuối tài khoản.
  • Nếu văn bản thông tin công bố không xuất hiện vì trình duyệt đã quan sát thấy một khoảnh khắc đăng ký trong quá khứ khi không có approved_clients.
  • Nếu tham số fields không bao gồm một hoặc nhiều trong số ba trường ("tên", "email" và "ảnh"), ví dụ: fields=[ ] hoặc fields=['name', 'picture']. Điều này cần thiết để tương thích ngược với các phương thức triển khai IdP cũ, trong đó chuỗi thông tin công bố phải luôn bao gồm cả ba trường.
is_auto_selected Nếu tự động xác thực lại được thực hiện trên RP, is_auto_selected sẽ cho biết "true". Nếu không, "false". Điều này sẽ giúp hỗ trợ thêm nhiều tính năng liên quan đến bảo mật. Ví dụ: một số người dùng có thể thích cấp độ bảo mật cao hơn, yêu cầu người dùng phải tham gia xác thực một cách rõ ràng. Nếu nhận được yêu cầu mã thông báo mà không có tính năng dàn xếp như vậy, thì IdP có thể xử lý yêu cầu theo cách khác. Ví dụ: trả về một mã lỗi để RP có thể gọi lại API FedCM bằng mediation: required.
fields (không bắt buộc) Mảng các chuỗi chỉ định thông tin người dùng ("tên", "email", "ảnh") mà RP cần IdP chia sẻ với họ.
Trình duyệt sẽ gửi fields, disclosure_text_showndisclosure_shown_for liệt kê các trường được chỉ định trong yêu cầu POST, như trong ví dụ sau.

Lưu ý: Thông số Trường được hỗ trợ từ Chrome 132.
params (không bắt buộc) Bất kỳ đối tượng JSON hợp lệ nào cho phép chỉ định các tham số khoá-giá trị tuỳ chỉnh bổ sung, ví dụ:
  • scope: Giá trị chuỗi chứa các quyền bổ sung mà RP cần yêu cầu, ví dụ: "drive.readonly calendar.readonly"
  • nonce: Chuỗi ngẫu nhiên do RP cung cấp để đảm bảo phản hồi được đưa ra cho yêu cầu cụ thể này. Ngăn chặn các cuộc tấn công phát lại.
  • Các thông số khoá-giá trị tuỳ chỉnh khác.
Khi trình duyệt gửi yêu cầu POST, giá trị params sẽ được chuyển đổi tuần tự thành JSON rồi mã hoá theo tỷ lệ phần trăm.

Lưu ý: Chrome 132 trở lên hỗ trợ Parameters API.

Ví dụ về tiêu đề HTTP:

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

  // disclosure_text_shown is set to 'false', as the 'name' field value is missing in 'fields' array
  // params value is serialized to JSON and then percent-encoded.
  account_id=123&client_id=client1234&disclosure_text_shown=false&is_auto_selected=true&params=%22%7B%5C%22nonce%5C%22%3A%5C%22nonce-value%5C%22%7D%22.%0D%0A4&disclosure_text_shown=true&fields=email,picture&disclosure_shown_for=email,picture

Sau khi nhận được yêu cầu, máy chủ phải:

  1. Trả lời yêu cầu bằng CORS (Chia sẻ tài nguyên trên nhiều nguồn gốc).
  2. Xác minh rằng yêu cầu chứa tiêu đề HTTP Sec-Fetch-Dest: webidentity.
  3. So khớp tiêu đề Origin với nguồn gốc RP do client_id xác định. Từ chối nếu không khớp.
  4. So khớp account_id với mã nhận dạng của tài khoản đã đăng nhập. Từ chối nếu các giá trị này không khớp.
  5. Phản hồi bằng mã thông báo. Nếu yêu cầu bị từ chối, hãy phản hồi bằng phản hồi lỗi.

IdP có thể quyết định cách phát hành mã thông báo. Nhìn chung, mã này được ký bằng thông tin như mã tài khoản, mã ứng dụng, nguồn gốc của tổ chức phát hành và số chỉ dùng một lần để RP có thể xác minh mã này là thật.

Trình duyệt dự kiến phản hồi JSON sẽ bao gồm thuộc tính sau:

Thuộc tính Mô tả
token Mã thông báo là một chuỗi chứa các thông báo xác nhận về việc xác thực.
continue_on URL chuyển hướng cho phép luồng đăng nhập nhiều bước.

Mã thông báo được trả về được trình duyệt chuyển đến RP để RP có thể xác thực.

  {
    // IdP can respond with a token to authenticate the user
    "token": "***********"
  }
Tính năng Tiếp tục

IdP có thể cung cấp URL chuyển hướng trong phản hồi điểm cuối xác nhận danh tính để cho phép quy trình đăng nhập nhiều bước. Điều này hữu ích khi IdP cần yêu cầu thêm thông tin hoặc quyền, ví dụ:

  • Quyền truy cập vào tài nguyên phía máy chủ của người dùng.
  • Xác minh rằng thông tin liên hệ là mới nhất.
  • Chế độ kiểm soát của cha mẹ.

Điểm cuối xác nhận mã nhận dạng có thể trả về một thuộc tính continue_on bao gồm đường dẫn tuyệt đối hoặc tương đối đến điểm cuối xác nhận mã nhận dạng.

  {
    // In the id_assertion_endpoint, instead of returning a typical
    // "token" response, the IdP decides that it needs the user to
    // continue on a popup window:
    "continue_on": "https://idp.example/continue_on_url"
  }

Nếu phản hồi chứa tham số continue_on, một cửa sổ bật lên mới sẽ mở ra và đưa người dùng đến đường dẫn đã chỉ định. Sau khi người dùng tương tác với trang continue_on, IdP sẽ gọi IdentityProvider.resolve() với mã thông báo được truyền dưới dạng đối số để có thể phân giải lời hứa từ lệnh gọi navigator.credentials.get() ban đầu:

  document.getElementById('example-button').addEventListener('click', async () => {
    let accessToken = await fetch('/generate_access_token.cgi');
    // Closes the window and resolves the promise (that is still hanging
    // in the relying party's renderer) with the value that is passed.
    IdentityProvider.resolve(accessToken);
  });

Sau đó, trình duyệt sẽ tự động đóng cửa sổ bật lên và trả mã thông báo về cho phương thức gọi API. Lệnh gọi IdentityProvider.resolve() một lần là cách duy nhất để cửa sổ mẹ (RP) và cửa sổ bật lên (IdP) giao tiếp.
Nếu người dùng từ chối yêu cầu, thì IdP có thể đóng cửa sổ bằng cách gọi IdentityProvider.close().

  IdentityProvider.close();

Continuation API yêu cầu sự tương tác rõ ràng của người dùng (lượt nhấp) để hoạt động. Dưới đây là cách hoạt động của Continuation API với các chế độ cách thức dàn xếp khác nhau:

  • chế độ thụ động:
    • mediation: 'optional' (mặc định): Continuation API sẽ chỉ hoạt động với một cử chỉ của người dùng, chẳng hạn như nhấp vào một nút trên trang hoặc trên giao diện người dùng FedCM. Khi quá trình tự động xác thực lại được kích hoạt mà không có cử chỉ của người dùng, cửa sổ bật lên sẽ không mở ra và lời hứa sẽ bị từ chối.
    • mediation: 'required': Luôn yêu cầu người dùng tương tác, vì vậy, Continuation API luôn hoạt động.
  • chế độ đang hoạt động:
    • Người dùng luôn phải kích hoạt. Continuation API tương thích.

Nếu vì lý do nào đó mà người dùng đã thay đổi tài khoản của họ trong cửa sổ bật lên (ví dụ: IdP cung cấp chức năng "sử dụng tài khoản khác" hoặc trong trường hợp uỷ quyền), thì lệnh gọi phân giải sẽ lấy một đối số thứ hai không bắt buộc cho phép thực hiện một số thao tác như:

  IdentityProvider.resolve(token, {accountId: '1234');
Trả về phản hồi lỗi

id_assertion_endpoint cũng có thể trả về một phản hồi "lỗi", trong đó có hai trường không bắt buộc:

  • code: IdP có thể chọn một trong các lỗi đã biết trong danh sách lỗi được chỉ định của OAuth 2.0 (invalid_request, unauthorized_client, access_denied, server_errortemporarily_unavailable) hoặc sử dụng bất kỳ chuỗi tuỳ ý nào. Nếu là trường hợp sau, Chrome sẽ hiển thị giao diện người dùng lỗi bằng thông báo lỗi chung và chuyển mã đến RP.
  • url: Xác định một trang web mà con người có thể đọc được, trong đó có thông tin về lỗi để cung cấp thêm thông tin về lỗi cho người dùng. Trường này rất hữu ích cho người dùng vì trình duyệt không thể cung cấp thông báo lỗi đa dạng thức trong giao diện người dùng tích hợp. Ví dụ: đường liên kết đến các bước tiếp theo hoặc thông tin liên hệ với bộ phận dịch vụ khách hàng. Nếu muốn tìm hiểu thêm về thông tin chi tiết về lỗi và cách khắc phục, người dùng có thể truy cập vào trang được cung cấp từ giao diện người dùng của trình duyệt để biết thêm thông tin. URL phải thuộc cùng một trang web với configURL của Nhà cung cấp dịch vụ nhận dạng (IdP).
  // id_assertion_endpoint response
  {
    "error" : {
      "code": "access_denied",
      "url" : "https://idp.example/error?type=access_denied"
    }
  }

Nhãn tài khoản tuỳ chỉnh

Với Nhãn tài khoản tuỳ chỉnh, IdP có thể chú thích tài khoản người dùng bằng nhãn và RP có thể chọn chỉ tìm nạp những tài khoản có nhãn cụ thể bằng cách chỉ định configURL cho nhãn cụ thể đó. Điều này có thể hữu ích khi một RP cần lọc ra các tài khoản theo tiêu chí cụ thể, ví dụ: chỉ hiển thị các tài khoản theo vai trò cụ thể như "developer" hoặc "hr".

Bạn có thể lọc tương tự bằng cách sử dụng các tính năng Gợi ý về miềnGợi ý đăng nhập, bằng cách chỉ định các tính năng đó trong lệnh gọi navigator.credentials.get(). Tuy nhiên, Nhãn tài khoản tuỳ chỉnh có thể lọc người dùng bằng cách chỉ định tệp cấu hình. Điều này đặc biệt hữu ích khi sử dụng nhiều configURL. Nhãn tài khoản tuỳ chỉnh cũng khác ở chỗ chúng được cung cấp từ máy chủ của Nhà cung cấp dịch vụ nhận dạng (IdP), thay vì từ Nhà cung cấp dịch vụ xác thực (RP), chẳng hạn như gợi ý đăng nhập hoặc miền.

Hãy xem xét một IdP muốn phân biệt giữa tài khoản "developer""hr". Để đạt được điều này, IdP cần hỗ trợ hai configURL tương ứng cho "developer""hr":

  • Tệp cấu hình dành cho nhà phát triển https://idp.example/developer/fedcm.json có nhãn "developer" và tệp cấu hình dành cho doanh nghiệp https://idp.example/hr/fedcm.json có nhãn "hr" như sau:
  // The developer config file at `https://idp.example/developer/fedcm.json`
  {
    "accounts_endpoint": "https://idp.example/accounts",
    "client_metadata_endpoint": "/client_metadata",
    "login_url": "https://idp.example/login",
    "id_assertion_endpoint": "/assertion",
    "accounts": {
      // Account label
      "include": "developer"
    }
  }
  // The hr config file at `https://idp.example/hr/fedcm.json`
  {
    "accounts_endpoint": "https://idp.example/accounts",
    "client_metadata_endpoint": "/client_metadata",
    "login_url": "https://idp.example/login",
    "id_assertion_endpoint": "/assertion",
    "accounts": {
      // Account label
      "include": "hr"
    }
  }
  • Với chế độ thiết lập như vậy, tệp đã biết phải bao gồm accounts_endpointlogin_url để cho phép nhiều configURL:
  {
    "provider_urls": [ "https://idp.example/fedcm.json" ],
    "accounts_endpoint": "https://idp.example/accounts",
    "login_url": "https://idp.example/login"
  }
  • Điểm cuối tài khoản IdP phổ biến (trong ví dụ này là https://idp.example/accounts) trả về danh sách tài khoản bao gồm một thuộc tính labels có nhãn được chỉ định trong một mảng cho mỗi tài khoản:
  {
  "accounts": [{
    "id": "123",
    "given_name": "John",
    "name": "John Doe",
    "email": "john_doe@idp.example",
    "picture": "https://idp.example/profile/123",
    "labels": ["developer"]
    }], [{
    "id": "4567",
    "given_name": "Jane",
    "name": "Jane Doe",
    "email": "jane_doe@idp.example",
    "picture": "https://idp.example/profile/4567",
    "labels": ["hr"]
    }]
  }

Khi muốn cho phép người dùng "hr" đăng nhập, RP có thể chỉ định configURL https://idp.example/hr/fedcm.json trong lệnh gọi navigator.credentials.get():

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

Do đó, người dùng chỉ có thể đăng nhập bằng mã tài khoản 4567. Mã tài khoản của 123 được trình duyệt ẩn một cách tự động để người dùng không được cung cấp một tài khoản không được IdP hỗ trợ trên trang web này.

  • Nhãn là chuỗi. Nếu mảng labels hoặc trường include chứa nội dung không phải là chuỗi, thì nội dung đó sẽ bị bỏ qua.
  • Nếu không chỉ định nhãn nào trong configURL, tất cả tài khoản sẽ xuất hiện trong bộ chọn tài khoản FedCM.
  • Nếu không chỉ định nhãn cho một tài khoản, thì tài khoản đó sẽ chỉ xuất hiện trong bộ chọn tài khoản nếu configURL cũng không chỉ định nhãn.
  • Nếu không có tài khoản nào khớp với nhãn được yêu cầu ở chế độ thụ động (tương tự như tính năng Gợi ý miền), hộp thoại FedCM sẽ hiển thị lời nhắc đăng nhập, cho phép người dùng đăng nhập vào tài khoản IdP. Đối với chế độ đang hoạt động, cửa sổ bật lên đăng nhập sẽ được mở trực tiếp.

Ngắt kết nối điểm cuối

Bằng cách gọi IdentityCredential.disconnect(), trình duyệt sẽ gửi một yêu cầu POST trên nhiều nguồn gốc bằng cookie có SameSite=None và loại nội dung là application/x-www-form-urlencoded đến điểm cuối ngắt kết nối này với thông tin sau:

Thuộc tính Mô tả
account_hint Gợi ý cho tài khoản IdP.
client_id Giá trị nhận dạng ứng dụng của RP.
  POST /disconnect.example HTTP/1.1
  Host: idp.example
  Origin: rp.example
  Content-Type: application/x-www-form-urlencoded
  Cookie: 0x123
  Sec-Fetch-Dest: webidentity

  account_hint=account456&client_id=rp123

Sau khi nhận được yêu cầu, máy chủ phải:

  1. Trả lời yêu cầu bằng CORS (Chia sẻ tài nguyên trên nhiều nguồn gốc).
  2. Xác minh rằng yêu cầu chứa tiêu đề HTTP Sec-Fetch-Dest: webidentity.
  3. So khớp tiêu đề Origin với nguồn gốc RP do client_id xác định. Từ chối nếu không khớp.
  4. So khớp account_hint với mã nhận dạng của các tài khoản đã đăng nhập.
  5. Ngắt kết nối tài khoản người dùng khỏi RP.
  6. Phản hồi trình duyệt bằng thông tin tài khoản người dùng đã xác định ở định dạng JSON.

Gói dữ liệu JSON phản hồi mẫu có dạng như sau:

  {
    "account_id": "account456"
  }

Thay vào đó, nếu IdP muốn trình duyệt ngắt kết nối tất cả tài khoản được liên kết với RP, hãy truyền một chuỗi không khớp với mã tài khoản nào, ví dụ: "*".

Điểm cuối siêu dữ liệu ứng dụng

Điểm cuối siêu dữ liệu ứng dụng của IdP trả về siêu dữ liệu của bên phụ thuộc, chẳng hạn như chính sách quyền riêng tư, điều khoản dịch vụ và biểu tượng biểu trưng của RP. RP phải cung cấp trước đường liên kết đến chính sách quyền riêng tư và điều khoản dịch vụ của họ cho IdP. Các đường liên kết này sẽ xuất hiện trong hộp thoại đăng nhập khi người dùng chưa đăng ký trên RP với IdP.

Trình duyệt gửi yêu cầu GET bằng client_id navigator.credentials.get mà không cần cookie. Ví dụ:

  GET /client_metadata.example?client_id=1234 HTTP/1.1
  Host: accounts.idp.example
  Origin: https://rp.example/
  Accept: application/json
  Sec-Fetch-Dest: webidentity

Sau khi nhận được yêu cầu, máy chủ phải:

  1. Xác định RP cho client_id.
  2. Trả lời bằng siêu dữ liệu ứng dụng.

Các thuộc tính cho điểm cuối siêu dữ liệu của ứng dụng bao gồm:

Thuộc tính Mô tả
privacy_policy_url (không bắt buộc) URL chính sách quyền riêng tư của RP.
terms_of_service_url (không bắt buộc) URL của điều khoản dịch vụ của RP.
icons (không bắt buộc) Mảng đối tượng, chẳng hạn như [{ "url": "https://rp.example/rp-icon.ico", "size": 40}]

Trình duyệt dự kiến một phản hồi JSON từ điểm cuối:

  {
    "privacy_policy_url": "https://rp.example/privacy_policy.html",
    "terms_of_service_url": "https://rp.example/terms_of_service.html",
    "icons": [{
          "url": "https://rp.example/rp-icon.ico",
          "size": 40
      }]
  }

Siêu dữ liệu ứng dụng được trả về sẽ do trình duyệt sử dụng và sẽ không có sẵn cho RP.

URL đăng nhập

Điểm cuối này được dùng để cho phép người dùng đăng nhập vào IdP.

Với API Trạng thái đăng nhập, IdP phải thông báo trạng thái đăng nhập của người dùng cho trình duyệt. Tuy nhiên, trạng thái có thể không đồng bộ, chẳng hạn như khi phiên hoạt động hết hạn. Trong trường hợp như vậy, trình duyệt có thể cho phép người dùng đăng nhập vào IdP một cách linh động thông qua URL trang đăng nhập được chỉ định bằng login_url của tệp cấu hình idp.

Hộp thoại FedCM hiển thị thông báo đề xuất đăng nhập, như trong hình sau.

A
Hộp thoại FedCM đề xuất đăng nhập vào IdP.

Khi người dùng nhấp vào nút Tiếp tục, trình duyệt sẽ mở một cửa sổ bật lên cho trang đăng nhập của IdP.

Hộp thoại FedCM mẫu.
Một hộp thoại mẫu xuất hiện sau khi nhấp vào nút đăng nhập vào IdP.

Hộp thoại này là một cửa sổ trình duyệt thông thường có cookie của bên thứ nhất. Mọi điều xảy ra trong hộp thoại đều tuỳ thuộc vào IdP và không có tay điều khiển cửa sổ nào để tạo yêu cầu giao tiếp giữa các nguồn gốc đến trang RP. Sau khi người dùng đăng nhập, IdP phải:

  • Gửi tiêu đề Set-Login: logged-in hoặc gọi API navigator.login.setStatus("logged-in") để thông báo cho trình duyệt rằng người dùng đã đăng nhập.
  • Gọi IdentityProvider.close() để đóng hộp thoại.
Người dùng đăng nhập vào một RP sau khi đăng nhập vào IdP bằng FedCM.

Thông báo cho trình duyệt về trạng thái đăng nhập của người dùng

Login Status API (API Trạng thái đăng nhập) là một cơ chế mà theo đó, một trang web, đặc biệt là một IdP, sẽ thông báo cho trình duyệt về trạng thái đăng nhập của người dùng trên IdP. Với API này, trình duyệt có thể giảm các yêu cầu không cần thiết đến IdP và giảm thiểu các cuộc tấn công theo thời gian tiềm ẩn.

Các IdP có thể báo hiệu trạng thái đăng nhập của người dùng cho trình duyệt bằng cách gửi tiêu đề HTTP hoặc bằng cách gọi API JavaScript khi người dùng đăng nhập vào IdP hoặc khi người dùng đăng xuất khỏi tất cả tài khoản IdP của họ. Đối với mỗi IdP (được xác định bằng URL cấu hình), trình duyệt sẽ giữ một biến ba trạng thái đại diện cho trạng thái đăng nhập với các giá trị có thể có:

  • logged-in
  • logged-out
  • unknown (mặc định)
Trạng thái đăng nhập Nội dung mô tả
logged-in Khi trạng thái đăng nhập của người dùng được đặt thành logged-in, RP gọi FedCM sẽ gửi yêu cầu đến điểm cuối tài khoản của IdP và hiển thị các tài khoản có sẵn cho người dùng trong hộp thoại FedCM.
logged-out Khi trạng thái đăng nhập của người dùng là logged-out, việc gọi FedCM sẽ không thành công mà không tạo yêu cầu đến điểm cuối tài khoản của IdP.
unknown (mặc định) Trạng thái unknown được đặt trước khi IdP gửi tín hiệu bằng API Trạng thái đăng nhập. Khi trạng thái là unknown, trình duyệt sẽ gửi yêu cầu đến điểm cuối tài khoản của IdP và cập nhật trạng thái dựa trên phản hồi từ điểm cuối tài khoản.

Để báo hiệu rằng người dùng đã đăng nhập, hãy gửi tiêu đề HTTP Set-Login: logged-in trong một thao tác điều hướng cấp cao nhất hoặc yêu cầu tài nguyên phụ trên cùng một trang web tại nguồn gốc của IdP:

  Set-Login: logged-in

Ngoài ra, hãy gọi phương thức JavaScript navigator.login.setStatus('logged-in') từ nguồn gốc của IdP trong một thao tác điều hướng cấp cao nhất:

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

Trạng thái đăng nhập của người dùng sẽ được đặt thành logged-in.

Để báo hiệu rằng người dùng đã đăng xuất khỏi tất cả tài khoản của họ, hãy gửi tiêu đề HTTP Set-Login: logged-out trong một thao tác điều hướng cấp cao nhất hoặc yêu cầu tài nguyên phụ trên cùng một trang web tại nguồn của IdP:

  Set-Login: logged-out

Ngoài ra, hãy gọi API JavaScript navigator.login.setStatus('logged-out') từ nguồn gốc của IdP trong một thao tác điều hướng cấp cao nhất:

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

Trạng thái đăng nhập của người dùng sẽ được đặt thành logged-out.

Trạng thái unknown được đặt trước khi IdP gửi tín hiệu bằng API Trạng thái đăng nhập. Trình duyệt gửi yêu cầu đến điểm cuối tài khoản của IdP và cập nhật trạng thái dựa trên phản hồi từ điểm cuối tài khoản:

  • Nếu điểm cuối trả về danh sách các tài khoản đang hoạt động, hãy cập nhật trạng thái thành logged-in và mở hộp thoại FedCM để hiển thị các tài khoản đó.
  • Nếu điểm cuối không trả về tài khoản nào, hãy cập nhật trạng thái thành logged-out và không thực hiện được lệnh gọi FedCM.

Cho phép người dùng đăng nhập thông qua quy trình đăng nhập động

Mặc dù IdP liên tục thông báo trạng thái đăng nhập của người dùng cho trình duyệt, nhưng trạng thái này có thể không đồng bộ, chẳng hạn như khi phiên hết hạn. Trình duyệt cố gắng gửi yêu cầu thông tin xác thực đến điểm cuối tài khoản khi trạng thái đăng nhập là logged-in, nhưng máy chủ không trả về tài khoản nào vì phiên không còn hoạt động. Trong trường hợp như vậy, trình duyệt có thể tự động cho phép người dùng đăng nhập vào IdP thông qua một cửa sổ bật lên.

Triển khai FedCM làm RP

Sau khi có cấu hình và điểm cuối của IdP, RP có thể gọi navigator.credentials.get() để yêu cầu cho phép người dùng đăng nhập vào RP bằng IdP.

Trước khi gọi API, bạn cần xác nhận rằng FedCM có trên trình duyệt của người dùng. Để kiểm tra xem FedCM có sẵn hay không, hãy gói mã này trong quá trình triển khai FedCM:

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

Để cho phép người dùng đăng nhập vào IdP trên RP bằng FedCM, RP có thể gọi navigator.credentials.get(), ví dụ:

  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;

Thuộc tính ngữ cảnh

Với thuộc tính context không bắt buộc, RP có thể sửa đổi chuỗi trong giao diện người dùng hộp thoại FedCM (ví dụ: "Đăng nhập vào rp.example…", "Sử dụng idp.example…") để phù hợp với các ngữ cảnh xác thực được xác định trước, ví dụ: Thuộc tính context có thể có các giá trị sau:

  • signin (mặc định)
  • signup
  • use
Sơ đồ giải thích các thành phần giao diện người dùng của hộp thoại FedCM: ở phía trên cùng bên trái, một biểu tượng sẽ hiển thị. Ở bên phải biểu tượng là một thành phần ngữ cảnh hiển thị thông báo "Đăng nhập vào RP bằng IdP". Ở dưới cùng là nút "Tiếp tục" có văn bản và màu nền tuỳ chỉnh.
Cách áp dụng bộ nhận diện thương hiệu cho hộp thoại FedCM

Ví dụ: việc đặt context thành use sẽ dẫn đến thông báo sau:

Hộp thoại FedCM hiển thị thông báo theo ngữ cảnh tuỳ chỉnh: thay vì "Đăng nhập" bằng FedCM, thông báo theo ngữ cảnh sẽ là "Sử dụng" FedCM.
Hộp thoại FedCM hiển thị thông báo theo ngữ cảnh tuỳ chỉnh.

Trình duyệt xử lý các trường hợp sử dụng đăng ký và đăng nhập theo cách khác nhau, tuỳ thuộc vào việc approved_clients có tồn tại trong phản hồi từ điểm cuối danh sách tài khoản hay không. Trình duyệt sẽ không hiển thị văn bản thông tin công bố "Để tiếp tục với ...." nếu người dùng đã đăng ký RP.
Thuộc tính providers nhận một mảng đối tượng IdentityProvider có các thuộc tính sau:

Thuộc tính nhà cung cấp

Thuộc tính providers nhận một mảng các đối tượng IdentityProvider có các thuộc tính sau:

Thuộc tính Mô tả
configURL (bắt buộc) Đường dẫn đầy đủ của tệp cấu hình IdP.
clientId (bắt buộc) Giá trị nhận dạng ứng dụng khách của RP do IdP phát hành.
nonce (không bắt buộc) Một chuỗi ngẫu nhiên để đảm bảo phản hồi được đưa ra cho yêu cầu cụ thể này. Ngăn chặn các cuộc tấn công phát lại.
loginHint (không bắt buộc) Bằng cách chỉ định một trong các giá trị login_hints do điểm cuối tài khoản cung cấp, hộp thoại FedCM sẽ hiển thị có chọn lọc tài khoản đã chỉ định.
domainHint (không bắt buộc) Bằng cách chỉ định một trong các giá trị domain_hints do điểm cuối tài khoản cung cấp, hộp thoại FedCM sẽ hiển thị có chọn lọc tài khoản đã chỉ định.
mode (không bắt buộc) Chuỗi chỉ định chế độ giao diện người dùng của FedCM. Thuộc tính này có thể là một trong các giá trị sau:
  • "active": Lời nhắc FedCM phải được bắt đầu bằng hoạt động tương tác của người dùng (chẳng hạn như nhấp vào một nút).
  • "passive": Lời nhắc FedCM sẽ được bắt đầu mà không cần người dùng tương tác trực tiếp.
Hãy xem trang tổng quan để tìm hiểu thêm về sự khác biệt giữa chế độ chủ động và thụ động.

Lưu ý: Thông số mode được hỗ trợ từ Chrome 132.
fields (không bắt buộc) Mảng chuỗi chỉ định thông tin người dùng ("tên", "email", "ảnh") mà RP cần IdP chia sẻ với họ.
Lưu ý: Chrome 132 trở lên hỗ trợ Field API.
parameters (không bắt buộc) Đối tượng tuỳ chỉnh cho phép chỉ định các tham số khoá-giá trị bổ sung:
  • scope: Giá trị chuỗi chứa các quyền bổ sung mà RP cần yêu cầu, ví dụ: "drive.readonly calendar.readonly"
  • nonce: Một chuỗi ngẫu nhiên để đảm bảo phản hồi được đưa ra cho yêu cầu cụ thể này. Ngăn chặn các cuộc tấn công phát lại.
  • Các thông số khoá-giá trị tuỳ chỉnh khác.

Lưu ý: parameters được hỗ trợ từ Chrome 132.

Chế độ đang hoạt động

FedCM hỗ trợ nhiều cấu hình chế độ trải nghiệm người dùng. Chế độ thụ động là chế độ mặc định và nhà phát triển không cần định cấu hình chế độ này.

Cách sử dụng FedCM ở chế độ đang hoạt động:

  1. Kiểm tra xem tính năng có hoạt động trong trình duyệt của người dùng hay không.
  2. Gọi API bằng một cử chỉ tạm thời của người dùng, chẳng hạn như một lượt nhấp vào nút.
  3. Truyền tham số mode vào lệnh gọi 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'
      }
    });
  }

Biểu tượng tuỳ chỉnh ở chế độ đang hoạt động

Chế độ đang hoạt động cho phép IdP đưa biểu tượng huy hiệu chính thức của RP vào trực tiếp trong phản hồi điểm cuối siêu dữ liệu của ứng dụng khách. RP phải cung cấp trước dữ liệu thương hiệu của họ.

Gọi FedCM từ bên trong một iframe trên nhiều nguồn gốc

Bạn có thể gọi FedCM từ trong một iframe trên nhiều nguồn gốc bằng cách sử dụng chính sách quyền identity-credentials-get, nếu khung mẹ cho phép. Để làm như vậy, hãy thêm thuộc tính allow="identity-credentials-get" vào thẻ iframe như sau:

  <iframe src="https://fedcm-cross-origin-iframe.glitch.me" allow="identity-credentials-get"></iframe>

Bạn có thể xem cách hoạt động của tính năng này trong ví dụ.

Nếu khung mẹ muốn hạn chế các nguồn gốc để gọi FedCM, bạn có thể gửi tiêu đề Permissions-Policy có danh sách các nguồn gốc được phép.

  Permissions-Policy: identity-credentials-get=(self "https://fedcm-cross-origin-iframe.glitch.me")

Bạn có thể tìm hiểu thêm về cách hoạt động của Chính sách quyền trong bài viết Kiểm soát các tính năng của trình duyệt bằng Chính sách quyền.

Login Hint API (API Gợi ý đăng nhập)

Bằng cách sử dụng Gợi ý đăng nhập, RP có thể đề xuất tài khoản mà người dùng nên đăng nhập. Điều này có thể hữu ích cho việc xác thực lại những người dùng không chắc chắn mình đã sử dụng tài khoản nào trước đây.

RP có thể hiển thị một tài khoản cụ thể theo lựa chọn bằng cách gọi navigator.credentials.get() với thuộc tính loginHint có một trong các giá trị login_hints được tìm nạp từ điểm cuối danh sách tài khoản, như trong mã mẫu sau:

  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'
      }]
    }
  });

Khi không có tài khoản nào khớp với loginHint, hộp thoại FedCM sẽ hiển thị lời nhắc đăng nhập, cho phép người dùng đăng nhập vào tài khoản IdP khớp với gợi ý do RP yêu cầu. Khi người dùng nhấn vào lời nhắc, một cửa sổ bật lên sẽ mở ra với URL đăng nhập được chỉ định trong tệp cấu hình. Sau đó, đường liên kết sẽ được thêm vào bằng gợi ý đăng nhập và tham số truy vấn gợi ý miền.

Domain Hint API (API Gợi ý về miền)

RP có thể chỉ hiển thị những tài khoản được liên kết với một miền nhất định. Điều này có thể hữu ích cho các RP bị hạn chế chỉ trong một miền của công ty.

Để chỉ hiển thị các tài khoản miền cụ thể, RP phải gọi navigator.credentials.get() bằng thuộc tính domainHint với một trong các giá trị domain_hints được tìm nạp từ điểm cuối danh sách tài khoản, như trong mã mẫu sau:

  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'
      }]
    }
  });

Khi không có tài khoản nào khớp với domainHint, hộp thoại FedCM sẽ hiển thị lời nhắc đăng nhập, cho phép người dùng đăng nhập vào tài khoản IdP khớp với gợi ý do RP yêu cầu. Khi người dùng nhấn vào lời nhắc, một cửa sổ bật lên sẽ mở ra với URL đăng nhập được chỉ định trong tệp cấu hình. Sau đó, đường liên kết sẽ được thêm vào bằng gợi ý đăng nhập và tham số truy vấn gợi ý miền.

Ví dụ về lời nhắc đăng nhập khi không có tài khoản nào khớp với domainHint.
Ví dụ về lời nhắc đăng nhập khi không có tài khoản nào khớp với domainHint.

Thông số tùy chỉnh

Tính năng Tham số tuỳ chỉnh cho phép RP cung cấp các tham số khoá-giá trị bổ sung cho điểm cuối xác nhận mã nhận dạng. Với API Thông số, RP có thể truyền các thông số bổ sung đến IdP để yêu cầu quyền cho các tài nguyên ngoài việc đăng nhập cơ bản. Việc truyền các tham số bổ sung có thể hữu ích trong các trường hợp sau:

  • RP cần yêu cầu các quyền bổ sung mà IdP có, chẳng hạn như địa chỉ thanh toán hoặc quyền truy cập vào lịch. Người dùng có thể uỷ quyền cho các quyền này thông qua quy trình trải nghiệm người dùng do IdP kiểm soát được khởi chạy bằng tính năng Tiếp tục. Sau đó, IdP sẽ chia sẻ thông tin này.

Để sử dụng API, RP sẽ thêm các tham số vào thuộc tính params dưới dạng một đối tượng trong lệnh gọi navigator.credentials.get():

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

Trình duyệt sẽ tự động dịch thông tin này thành một yêu cầu POST tới IdP với các tham số dưới dạng một đối tượng JSON được chuyển đổi tuần tự được mã hoá URL:

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

Nếu RP cần thêm quyền, thì IdP có thể cung cấp đường liên kết chuyển hướng. Ví dụ: trong node.js:

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

Trường

RP có thể chỉ định thông tin người dùng (bất kỳ tổ hợp nào của tên, địa chỉ email và ảnh hồ sơ) mà họ cần IdP chia sẻ với họ. Thông tin được yêu cầu sẽ được đưa vào giao diện người dùng thông tin công bố của hộp thoại FedCM. Người dùng sẽ thấy thông báo cho họ biết rằng idp.example sẽ chia sẻ thông tin được yêu cầu với rp.example nếu người dùng chọn đăng nhập.

Hộp thoại chế độ đang hoạt động của FedCM hiển thị thông báo công bố. Để tiếp tục, nhà cung cấp danh tính sẽ chia sẻ địa chỉ email và ảnh hồ sơ của người dùng với trang web.
Thông báo công bố ở chế độ đang hoạt động: RP yêu cầu IdP chỉ chia sẻ email và ảnh hồ sơ của người dùng.

Để sử dụng tính năng Trường, RP phải thêm một mảng fields trong lệnh gọi navigator.credentials.get(). Các trường này có thể chứa bất kỳ hoán vị nào của name, emailpicture. Bạn có thể mở rộng phạm vi này để thêm các giá trị khác trong tương lai. Yêu cầu có fields sẽ có dạng như sau:

  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',

      },
    }
  });

Trình duyệt sẽ tự động dịch thông tin này thành một yêu cầu HTTP đến điểm cuối xác nhận mã nhận dạng, bao gồm tham số fields do RP chỉ định, với các trường mà trình duyệt đã tiết lộ cho người dùng trong tham số disclosure_shown_for. Để tương thích ngược, trình duyệt cũng sẽ gửi disclosure_text_shown=true nếu văn bản thông tin công bố đã hiển thị và các trường được yêu cầu bao gồm cả ba trường: 'name', 'email''picture'.

  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

Nếu fields là một mảng trống, thì tác nhân người dùng sẽ bỏ qua giao diện người dùng thông tin công bố.

Hộp thoại chế độ thụ động FedCM không hiển thị thông báo trên giao diện người dùng về việc công bố.
Thông báo công bố không xuất hiện ở chế độ thụ động. Trong quy trình nút, giao diện người dùng thông tin công bố sẽ bị bỏ qua hoàn toàn.

Điều này xảy ra ngay cả khi phản hồi từ điểm cuối tài khoản không chứa mã ứng dụng khớp với RP trong approved_clients.

Trong trường hợp này, disclosure_text_shown được gửi đến điểm cuối xác nhận mã nhận dạng là sai trong phần nội dung HTTP:

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

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

Hiển thị thông báo lỗi

Đôi khi, IdP có thể không thể phát hành mã thông báo vì lý do chính đáng, chẳng hạn như khi ứng dụng không được uỷ quyền hoặc máy chủ tạm thời không hoạt động. Nếu IdP trả về phản hồi "lỗi", thì RP có thể phát hiện lỗi đó và Chrome có thể thông báo cho người dùng bằng cách hiển thị giao diện người dùng trình duyệt với thông tin lỗi do IdP cung cấp.

A
Hộp thoại FedCM hiển thị thông báo lỗi sau khi người dùng không đăng nhập được. Chuỗi này được liên kết với loại lỗi.
  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;
  }

Tự động xác thực lại người dùng sau khi xác thực ban đầu

Tính năng tự động xác thực lại bằng FedCM (viết tắt là "tự động xác thực lại") có thể cho phép người dùng tự động xác thực lại khi họ quay lại sau khi xác thực lần đầu bằng FedCM. "Quy trình xác thực ban đầu" ở đây có nghĩa là người dùng tạo một tài khoản hoặc đăng nhập vào trang web của RP bằng cách nhấn vào nút "Tiếp tục dưới dạng..." trên hộp thoại đăng nhập của FedCM lần đầu tiên trên cùng một phiên bản trình duyệt.

Mặc dù trải nghiệm người dùng rõ ràng là hợp lý trước khi người dùng tạo tài khoản liên kết để ngăn chặn việc theo dõi (đây là một trong những mục tiêu chính của FedCM), nhưng trải nghiệm này sẽ trở nên rườm rà không cần thiết sau khi người dùng đã trải qua một lần: sau khi người dùng cấp quyền cho phép giao tiếp giữa RP và IdP, sẽ không có lợi ích nào về quyền riêng tư hoặc bảo mật khi thực thi một xác nhận rõ ràng khác của người dùng về nội dung mà họ đã xác nhận trước đó.

Với tính năng tự động xác thực lại, trình duyệt sẽ thay đổi hành vi tuỳ thuộc vào tuỳ chọn bạn chỉ định cho mediation khi gọi 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;

mediationmột thuộc tính trong API quản lý thông tin xác thực, thuộc tính này hoạt động theo cách tương tự như đối với PasswordCredentialFederatedCredential, đồng thời cũng được PublicKeyCredential hỗ trợ một phần. Thuộc tính này chấp nhận 4 giá trị sau:

  • 'optional'(mặc định): Tự động xác thực lại nếu có thể, yêu cầu dàn xếp nếu không. Bạn nên chọn tuỳ chọn này trên trang đăng nhập.
  • 'required': Luôn yêu cầu dàn xếp để tiếp tục, ví dụ: nhấp vào nút "Tiếp tục" trên giao diện người dùng. Chọn tuỳ chọn này nếu bạn muốn người dùng cấp quyền một cách rõ ràng mỗi khi cần xác thực.
  • 'silent': Tự động xác thực lại nếu có thể, âm thầm không thành công mà không yêu cầu dàn xếp nếu không. Bạn nên chọn tuỳ chọn này trên các trang không phải là trang đăng nhập chuyên dụng nhưng là nơi bạn muốn người dùng luôn đăng nhập, ví dụ: trang mặt hàng trên trang web vận chuyển hoặc trang bài viết trên trang web tin tức.
  • 'conditional': Dùng cho WebAuthn và hiện không dùng được cho FedCM.

Với lệnh gọi này, tính năng tự động xác thực lại sẽ diễn ra trong các điều kiện sau:

  • Bạn có thể sử dụng FedCM. Ví dụ: người dùng chưa tắt FedCM trên toàn cục hoặc cho RP trong phần cài đặt.
  • Người dùng chỉ sử dụng một tài khoản có API FedCM để đăng nhập vào trang web trên trình duyệt này.
  • Người dùng đã đăng nhập vào IdP bằng tài khoản đó.
  • Quá trình tự động xác thực lại không xảy ra trong vòng 10 phút qua.
  • RP chưa gọi navigator.credentials.preventSilentAccess() sau khi đăng nhập trước đó.

Khi các điều kiện này được đáp ứng, quá trình tự động xác thực lại người dùng sẽ bắt đầu ngay khi navigator.credentials.get() FedCM được gọi.

Khi mediation: optional, tính năng tự động xác thực lại có thể không hoạt động vì những lý do mà chỉ trình duyệt mới biết; RP có thể kiểm tra xem tính năng tự động xác thực lại có được thực hiện hay không bằng cách kiểm tra thuộc tính isAutoSelected.

Điều này sẽ giúp bạn đánh giá hiệu suất của API và cải thiện trải nghiệm người dùng cho phù hợp. Ngoài ra, khi không có, người dùng có thể được nhắc đăng nhập bằng tính năng dàn xếp người dùng rõ ràng, đây là một luồng có mediation: required.

Người dùng tự động xác thực lại thông qua FedCM.

Thực thi tính năng dàn xếp bằng preventSilentAccess()

Việc tự động xác thực lại người dùng ngay sau khi họ đăng xuất sẽ không mang lại trải nghiệm tốt cho người dùng. Đó là lý do FedCM có khoảng thời gian yên tĩnh 10 phút sau khi tự động xác thực lại để ngăn hành vi này. Điều này có nghĩa là tính năng tự động xác thực lại sẽ xảy ra tối đa một lần trong mỗi 10 phút, trừ phi người dùng đăng nhập lại trong vòng 10 phút. RP phải gọi navigator.credentials.preventSilentAccess() để yêu cầu trình duyệt tắt tính năng tự động xác thực lại khi người dùng đăng xuất khỏi RP một cách rõ ràng, chẳng hạn như bằng cách nhấp vào nút đăng xuất.

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

Người dùng có thể chọn không sử dụng tính năng tự động xác thực lại trong phần cài đặt

Người dùng có thể chọn không sử dụng tính năng tự động xác thực lại trong trình đơn cài đặt:

  • Trên Chrome dành cho máy tính, hãy chuyển đến chrome://password-manager/settings > Tự động đăng nhập.
  • Trên Chrome cho Android, hãy mở phần Cài đặt > Trình quản lý mật khẩu > Nhấn vào biểu tượng bánh răng ở góc trên cùng bên phải > Tự động đăng nhập.

Bằng cách tắt nút bật/tắt, người dùng có thể chọn không sử dụng hành vi tự động xác thực lại. Chế độ cài đặt này được lưu trữ và đồng bộ hoá trên các thiết bị, nếu người dùng đã đăng nhập vào một Tài khoản Google trên phiên bản Chrome và đã bật tính năng đồng bộ hoá.

Ngắt kết nối IdP khỏi RP

Nếu người dùng đã đăng nhập vào RP bằng IdP thông qua FedCM, thì trình duyệt sẽ ghi nhớ mối quan hệ này cục bộ dưới dạng danh sách các tài khoản đã kết nối. RP có thể bắt đầu ngắt kết nối bằng cách gọi hàm IdentityCredential.disconnect(). Bạn có thể gọi hàm này từ khung RP cấp cao nhất. RP cần truyền configURL, clientId mà nó sử dụng trong IdP và accountHint để ngắt kết nối IdP. Gợi ý tài khoản có thể là một chuỗi tuỳ ý miễn là điểm cuối ngắt kết nối có thể xác định tài khoản, ví dụ: địa chỉ email hoặc mã nhận dạng người dùng không nhất thiết phải khớp với mã nhận dạng tài khoản mà điểm cuối danh sách tài khoản đã cung cấp:

  // 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() trả về một Promise. Lời hứa này có thể gửi một ngoại lệ vì những lý do sau:

  • Người dùng chưa đăng nhập vào RP bằng IdP thông qua FedCM.
  • API được gọi từ trong một iframe không có chính sách về quyền FedCM.
  • configURL không hợp lệ hoặc thiếu điểm cuối ngắt kết nối.
  • Không kiểm tra được Chính sách bảo mật nội dung (CSP).
  • Có một yêu cầu ngắt kết nối đang chờ xử lý.
  • Người dùng đã tắt FedCM trong phần cài đặt trình duyệt.

Khi điểm cuối ngắt kết nối của IdP trả về phản hồi, RP và IdP sẽ bị ngắt kết nối trên trình duyệt và lời hứa sẽ được giải quyết. Mã của các tài khoản đã ngắt kết nối được chỉ định trong phản hồi từ điểm cuối ngắt kết nối.