Hướng dẫn cho nhà phát triển về API Quản lý thông tin xác thực liên kết

Tìm hiểu cách sử dụng FedCM để liên kết danh tính nhằm bảo đảm quyền riêng tư.

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ụ nhận dạng liên kết (chẳng hạn như "Đăng nhập bằng..."), trong đó người dùng có thể đă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ụ nhận dạng hoặc trang web.

Để tìm hiểu thêm về các trường hợp sử dụng, luồng người dùng và lộ trình API của FedCM, hãy xem phần giới thiệu về API FedCM.

Môi trường phát triển FedCM

Bạn cần có ngữ cảnh bảo mật (HTTPS hoặc localhost) trên cả IdP và RP trong Chrome để sử dụng FedCM.

Gỡ lỗi mã trong Chrome trên Android

Thiết lập và chạy máy chủ cục bộ để gỡ lỗi mã FedCM. Bạn có thể truy cập vào máy chủ này trong Chrome trên thiết bị Android được kết nối bằng cáp USB có tính năng chuyển tiếp cổng.

Bạn có thể sử dụng Công cụ của Chrome cho nhà phát triển trên máy tính để gỡ lỗi Chrome trên Android bằng cách làm theo hướng dẫn tại bài viết Gỡ lỗi từ xa cho thiết bị Android.

Chặn cookie của bên thứ ba trên Chrome

Mô phỏng việc loại bỏ cookie của bên thứ ba bằng cách định cấu hình Chrome để chặn các cookie đó
Mô phỏng loại bỏ cookie của bên thứ ba bằng cách định cấu hình Chrome để chặn các cookie đó

Bạn có thể kiểm thử cách FedCM hoạt động mà không cần cookie của bên thứ ba trên Chrome trước khi FedCM được thực thi.

Để chặn cookie của bên thứ ba, hãy sử dụng Chế độ ẩn danh hoặc chọn "Chặn cookie của bên thứ ba" trong phần cài đặt của máy tính tại chrome://settings/cookies hoặc trên thiết bị di động bằng cách chuyển đến phần Cài đặt > Cài đặt trang web > Cookie.

Sử dụng API FedCM

Bạn sẽ tích hợp với FedCM bằng cách tạo một tệp phổ biến, tệp cấu hình và điểm cuối cho danh sách tài khoản, phát hành xác nhậnsiêu dữ liệu ứng dụng (không bắt buộc).

Từ đó, FedCM hiển thị các API JavaScript mà bên bị hạn chế có thể dùng để đăng nhập bằ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.

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 phổ biến tại https://idp.example/.well-known/web-identity cũng như tệp cấu hình của IdP. Dưới đây là một ví dụ về nội dung tệp phổ biến:

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

Tệp JSON phải chứa thuộc tính provider_urls có một mảng gồm các URL tệp cấu hình IdP có thể được chỉ định làm một phần đường dẫn của configURL trong navigator.credentials.get theo RP. Số lượng chuỗi URL trong mảng bị giới hạn ở một, nhưng điều này có thể thay đổi theo ý kiến phản hồi của bạn trong tương lai.

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

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 sẽ lưu trữ tệp cấu hình này 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 thuộc 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;

Chỉ định một URL đầy đủ cho vị trí tệp cấu hình nhà cung cấp danh tính làm configURL. Khi navigator.credentials.get() được gọi trên RP, trình duyệt sẽ tìm nạp tệp cấu hình bằng yêu cầu GET không có tiêu đề Origin hoặc tiêu đề Referer. Yêu cầu này không có cookie và không tuân theo lệnh chuyển hướng. Việc này giúp ngăn chặn một cách hiệu quả 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

Trình duyệt sẽ chờ phản hồi JSON từ IdP, trong đó có 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 của tài khoản.
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 sử dụng thương hiệu để đặt màu nền của nút "Continue as..." (Tiếp tục dưới dạng...). 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 phù hợp, cụ thể là hex-color, hsl(), rgb() hoặc named-color.
branding.icons (không bắt buộc) Tuỳ chọn xây dựng thương hiệu để đặt đối tượng biểu tượng, xuất hiện trong hộp thoại đăng nhập. Đối tượng biểu tượng là một mả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 25.

RP có thể sửa đổi chuỗi trong giao diện người dùng hộp thoại FedCM thông qua giá trị identity.context cho navigator.credentials.get() để phù hợp với ngữ cảnh xác thực được xác định trước. Thuộc tính không bắt buộc có thể là một trong các thuộc tính "signin" (mặc định), "signup", "use" hoặc "continue".

Cách áp dụng thương hiệu cho hộp thoại FedCM
Cách áp dụng bộ nhận diện thương hiệu cho hộp thoại FedCM

Dưới đây là một nội dung phản hồi mẫu từ 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
    }]
  }
}

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 IdP:

Điểm cuối của IdP (nhà cung cấp danh tính)
Các điểm cuối của IdP

Đ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 đang đă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.php HTTP/1.1
Host: accounts.idp.example
Accept: application/json
Cookie: 0x23223
Sec-Fetch-Dest: webidentity

Khi nhận được yêu cầu, máy chủ cần:

  1. Xác minh rằng yêu cầu có chứa tiêu đề HTTP Sec-Fetch-Dest: webidentity.
  2. So khớp cookie của phiên hoạt động 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 mã ứng dụng khách 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.

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",
    "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"]
  }]
}

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 của siêu dữ liệu ứng dụng

Điểm cuối siêu dữ liệu ứng dụng của IdP sẽ trả về siêu dữ liệu của bên tin cậy, chẳng hạn như chính sách quyền riêng tư và điều khoản dịch vụ của bên bị hạn chế. 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 cách sử dụng client_id navigator.credentials.get mà không có cookie. Ví dụ:

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

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.

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

Siêu dữ liệu của ứng dụng được trả về sẽ được trình duyệt sử dụng và sẽ không dùng được 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 một trang web RP bằng lệnh gọi navigator.credentials.get(), trình duyệt sẽ gửi yêu cầu POST có cookie có SameSite=None và loại nội dung application/x-www-form-urlencoded đến điểm cuối này kèm theo 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 khách 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.
nonce (không bắt buộc) Số chỉ dùng một lần của yêu cầu do RP cung cấp.
disclosure_text_shown Kết quả bằng một chuỗi "true" hoặc "false" (thay vì một boolean). Kết quả là "false" nếu văn bản công bố không xuất hiện. Điều này xảy ra khi mã ứng dụng khách của RP được đưa vào danh sách thuộc tính approved_clients của phản hồi từ điểm cuối của tài khoản hoặc nếu trình duyệt đã quan sát thấy một khoảnh khắc đăng ký trong quá khứ mà không có approved_clients.
is_auto_selected Nếu bạn thực hiện tự động xác thực lại trên RP, is_auto_selected sẽ cho biết "true". Nếu không, "false". Điều này rất hữu ích trong việc hỗ trợ thêm các 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, đòi hỏi người dùng phải dàn xếp rõ ràng trong quá trình xác thực. Nếu một IdP nhận được yêu cầu về mã thông báo khi chưa dàn xếp như vậy, thì họ 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.

Ví dụ về tiêu đề 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

Khi nhận được yêu cầu, máy chủ cần:

  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 có 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ã của tài khoản đã đăng nhập. Từ chối nếu chúng không phù hợp.
  5. Hãy trả lời bằng một 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.

Cách phát hành mã thông báo sẽ tuỳ thuộc vào IdP, nhưng nhìn chung, mã đó được ký bằng các thông tin như mã tài khoản, mã ứng dụng khách, nguồn gốc của nhà phát hành, nonce, để RP có thể xác minh mã thông báo đó là thật.

Trình duyệt mong đợi nhận được phản hồi JSON bao gồm thuộc tính sau:

Thuộc tính Mô tả
token (bắt buộc) Mã thông báo là một chuỗi chứa các tuyên bố về việc xác thực.
{
  "token": "***********"
}

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

Trả về phản hồi lỗi

id_assertion_endpoint cũng có thể trả về 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 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 sau này, Chrome sẽ hiển thị giao diện người dùng lỗi với thông báo lỗi chung và chuyển mã đó đến RP.
  • url: Mã này xác định một trang web mà con người có thể đọc được cùng với thông tin về lỗi nhằm cung cấp thêm thông tin về lỗi đó cho người dùng. Trường này hữu ích cho người dùng vì trình duyệt không thể cung cấp các thông báo lỗi nhiều định dạng trong giao diện người dùng gốc. Ví dụ: đường liên kết cho các bước tiếp theo, thông tin liên hệ của bộ phận dịch vụ khách hàng, v.v. Nếu muốn tìm hiểu thêm về chi tiết lỗi và cách khắc phục lỗi, người dùng có thể truy cập trang được cung cấp từ giao diện người dùng của trình duyệt để biết thêm chi tiết. URL này phải thuộc cùng một trang web với IdP configURL.
// id_assertion_endpoint response
{
  "error" : {
     "code": "access_denied",
     "url" : "https://idp.example/error?type=access_denied"
  }
}

Ngắt kết nối thiết bị đầu 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 bên bị hạn chế.
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

Khi nhận được yêu cầu, máy chủ cần:

  1. Phản hồi yêu cầu bằng tính nă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 có 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 chúng 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.

Ví dụ về tải trọng JSON phản hồi sẽ 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 đã liên kết với RP, hãy truyền một chuỗi không khớp với bất kỳ mã tài khoản nào, chẳng hạn như "*".

URL đăng nhập

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 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ị một thông báo gợi ý đăng nhập, như trong hình sau.

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

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

Ví dụ về hộp thoại FedCM.
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 việc diễn ra trong hộp thoại này đều tuỳ thuộc vào IdP (nhà cung cấp danh tính) và không có ô điều khiển cửa sổ nào để gửi yêu cầu giao tiếp từ nhiều nguồn đế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 bên bị hạn chế sau khi đăng nhập vào IdP (nhà cung cấp danh tính) 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 trên nhà cung cấp danh tính

API Trạng thái đăng nhập là một cơ chế trong đó một trang web, đặc biệt là một IdP, 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. Nhờ 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 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ó là logged-in, logged-outunknown. Trạng thái mặc định là unknown.

Để 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 API 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")

Các lệnh gọi này ghi lại trạng thái đăng nhập của người dùng dưới dạng 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ẽ đưa ra các 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.

Để 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 thanh đ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-out

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

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

Các lệnh gọi này ghi lại trạng thái đăng nhập của người dùng dưới dạng 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ẽ tự động không thực hiện được mà không yêu cầu điểm cuối tài khoản của IdP.

Trạng thái unknown được đặt trước khi IdP gửi một tín hiệu bằng API Trạng thái đăng nhập. Unknown được giới thiệu để quá trình chuyển đổi diễn ra hiệu quả hơn, vì người dùng có thể đã đăng nhập vào IdP khi API này được phân phối. Có thể IdP không có cơ hội báo hiệu điều này cho trình duyệt vào thời điểm FedCM được gọi lần đầu tiên. Trong trường hợp này, Chrome 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 của tài khoản:

  • Nếu điểm cuối trả về danh sách 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 một luồng đă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 sẽ cố gắng gửi một yêu cầu đã được xác thực đến điểm cuối của 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 nữa. 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.

Đăng nhập vào bên phụ thuộc bằng nhà cung cấp danh tính

Sau khi có cấu hình và điểm cuối của IdP, bên bị hạn chế 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ó sẵn 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 xung quanh quá trình triển khai FedCM:

if ('IdentityCredential' in window) {
  // If the feature is available, take action
}

Để yêu cầu cho phép người dùng đăng nhập vào IdP từ RP, hãy làm như sau, ví dụ:

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

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 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 của RP do IdP (nhà cung cấp danh tính) cấp.
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 các điểm cuối của tài khoản cung cấp, hộp thoại FedCM sẽ hiển thị một cách có chọn lọc tài khoản được 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 được 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 dòng thông tin công bố "To tiếp tục với ...." nếu người dùng đã đăng ký bên bị hạn chế.

Trạng thái đăng ký được xác định dựa trên việc các điều kiện sau đây đã được đáp ứng hay chưa:

  • Nếu approved_clients bao gồm clientId của RP.
  • Nếu trình duyệt ghi nhớ rằng người dùng đã đăng ký RP.
Người dùng đăng nhập vào một RP bằng FedCM.

Khi RP gọi navigator.credentials.get(), các hoạt động sau sẽ diễn ra:

  1. Trình duyệt gửi yêu cầu và tìm nạp một số tài liệu:
    1. Tệp phổ biếntệp cấu hình nhà cung cấp danh tính (IdP) khai báo các điểm cuối.
    2. Danh sách tài khoản.
    3. Không bắt buộc: URL của chính sách quyền riêng tư và điều khoản dịch vụ của RP, được truy xuất từ điểm cuối siêu dữ liệu của ứng dụng.
  2. Trình duyệt hiển thị danh sách tài khoản mà người dùng có thể dùng để đăng nhập, cũng như điều khoản dịch vụ và chính sách quyền riêng tư (nếu có).
  3. Sau khi người dùng chọn một tài khoản để đăng nhập, một yêu cầu đến điểm cuối xác nhận danh tính sẽ được gửi đến IdP để truy xuất mã thông báo.
  4. RP có thể xác thực mã thông báo để xác thực người dùng.
lệnh gọi API đăng nhập
lệnh gọi API đăng nhập

RP dự kiến sẽ hỗ trợ các trình duyệt không hỗ trợ FedCM, do đó, người dùng có thể sử dụng quy trình đăng nhập hiện có, không phải FedCM. Cho đến khi cookie của bên thứ ba bị loại bỏ hoàn toàn, vấn đề này sẽ không còn xảy ra.

Sau khi máy chủ RP xác thực mã thông báo, RP có thể đăng ký người dùng hoặc cho phép họ đăng nhập và bắt đầu một phiên mới.

API Gợi ý đăng nhập

Sau khi người dùng đăng nhập, đôi khi bên phụ thuộc (RP) sẽ yêu cầu người dùng xác thực lại. Tuy nhiên, người dùng có thể không chắc chắn mình đang sử dụng tài khoản nào. Nếu RP có thể chỉ định tài khoản để đăng nhập, thì người dùng sẽ dễ dàng chọn tài khoản hơn.

Các RP có thể hiển thị chọn lọc một tài khoản cụ thể bằng cách gọi navigator.credentials.get() bằng thuộc tính loginHint với một trong các giá trị login_hints được tìm nạp từ điểm cuối của 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",
      nonce: nonce,
      loginHint : "demo1@example.com"
    }]
  }
});

Khi không có tài khoản nào khớp với loginHint, hộp thoại FedCM sẽ hiện lời nhắc đăng nhập, cho phép người dùng đăng nhập vào một tài khoản IdP phù hợp với gợi ý mà 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 cùng 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à các tham số truy vấn gợi ý về miền.

API Gợi ý tên miền

Có trường hợp RP đã biết rằng chỉ những tài khoản liên kết với một miền nhất định mới được phép đăng nhập vào trang web. Điều này đặc biệt phổ biến trong các tình huống của doanh nghiệp khi trang web được truy cập bị hạn chế ở miền của công ty. Nhằm mang lại trải nghiệm tốt hơn cho người dùng, FedCM API cho phép RP chỉ hiển thị những tài khoản có thể dùng để đăng nhập vào RP đó. Điều này giúp ngăn chặn các trường hợp người dùng cố gắng đăng nhập vào RP bằng một tài khoản bên ngoài miền công ty, chỉ nhận được thông báo lỗi sau đó (hoặc im lặng khi thông tin đăng nhập không hoạt động) do không sử dụng đúng loại tài khoản.

Các RP có thể chỉ hiển thị chọn lọc các tài khoản phù hợp bằng cách gọi navigator.credentials.get() bằng thuộc tính domainHint có một trong các giá trị domain_hints được tìm nạp từ điểm cuối của 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",
      nonce: nonce,
      domainHint : "corp.example"
    }]
  }
});

Khi không có tài khoản nào khớp với domainHint, hộp thoại FedCM sẽ hiện lời nhắc đăng nhập, cho phép người dùng đăng nhập vào một tài khoản IdP phù hợp với gợi ý mà 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à các tham số truy vấn gợi ý về 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.

Hiện thông báo lỗi

Đôi khi, IdP có thể không thể phát hành mã thông báo vì những lý do hợp lệ, chẳng hạn như khi ứng dụng không được uỷ quyền, máy chủ tạm thời không hoạt động. Nếu IdP trả về phản hồi "lỗi", thì bên bị hạn chế có thể phát hiện được phản hồi đó, cũng như Chrome sẽ thông báo cho người dùng bằng cách hiển thị giao diện người dùng của trình duyệt có 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 lần 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. "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 bên bị hạn chế bằng cách nhấn vào nút "Continue as..." (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 của mình tuỳ thuộc vào tuỳ chọn mà 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, 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 dự kiến người dùng của bạn sẽ cấp quyền một cách rõ ràng mỗi khi họ cần được xác thực.
  • 'silent': Tự động xác thực lại nếu có thể, tự động 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 lựa chọn này trên các trang không phải là trang đăng nhập chuyên biệt, nhưng là nơi bạn muốn duy trì trạng thái đăng nhập của người dùng (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': Đang dùng cho WebAuthn và hiện chưa 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 diễn ra trong vòng 10 phút vừa 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, hệ thống sẽ bắt đầu cố gắng tự động xác thực lại người dùng 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 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 rất hữu ích để đá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à quá trình tự động xác thực lại diễn 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 rõ ràng 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 Android Chrome, 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.

Khi 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 cùng nhau. 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(). Hàm này có thể được gọi từ khung RP cấp cao nhất. RP cần truyền một configURL, clientId mà nền tảng này dùng trong IdP, và một accountHint để nhà cung cấp danh tính bị ngắt kết nối. 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ề Promise. Lời hứa này có thể gửi ra một trường hợp 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ề một 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 phân giải. 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.

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

Bạn có thể gọi FedCM từ trong một iframe 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. Để thực hiện việc nà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 về 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 về quyền.