עדכונים של FedCM: גרסאות מקור לניסיון של חבילת Continuation API והענקה אוטומטית של Storage Access API

החל מגרסה 126 של Chrome, המפתחים יכולים להתחיל להריץ גרסת מקור לניסיון של חבילת תכונות של Federated Credential Management API (FedCM) שמאפשרות שימוש בתרחישים לדוגמה מסוימים של הרשאה. החבילה מורכבת מ-Continuation API ומ-Parameters API, שמאפשרים חוויה דומה לתהליך ההרשאה של OAuth, שכוללת תיבת דו-שיח של הרשאה שמספקת ספק זהויות (IdP). החבילה כוללת גם שינויים אחרים כמו Fields API, כתובות URL מרובות ו-Custom Account Labels. החל מגרסה 126 של Chrome, אנחנו משיקים גם גרסת טרום-השקה של Storage Access API ‏(SAA) שמעניקה באופן אוטומטי הרשאות לבקשות SAA אם המשתמש נכנס לחשבון באמצעות FedCM בעבר.

גרסת מקור לניסיון: חבילת FedCM Continuation API

חבילת FedCM Continuation API מורכבת מכמה תוספי FedCM:

Continuation API

משתמש נכנס לגורם מוגבל ואז מאשר דרך מצב הלחצן.

אפשר לעיין בהדגמה של ה-API ב-Glitch.

Continuation API מאפשר לנקודת הקצה של טענת הנכוֹנוּת של המזהה ב-IdP להחזיר, אם רוצים, כתובת URL ש-FedCM ידפיס כדי לאפשר למשתמש להמשיך בתהליך הכניסה שמורכב מכמה שלבים. כך ה-IdP יכול לבקש מהמשתמש להעניק הרשאות לצד הנסמך (RP) מעבר למה שאפשר לעשות בממשק המשתמש הקיים של FedCM, כמו גישה למשאבים של המשתמש בצד השרת.

בדרך כלל, נקודת הקצה של טענת הנכוֹנוּת של הזהות מחזירה אסימון שנחוץ לאימות.

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

עם זאת, באמצעות ממשק ה-API של המשך, נקודת הקצה (endpoint) של טענת הנכוֹנוּת (assertion) של המזהה יכולה להחזיר נכס continue_on שכולל נתיב מוחלט או נתיב יחסי לנקודת הקצה של טענת הנכונות (assertion) של המזהה.

{
  // In the id_assertion_endpoint, instead of returning a typical
  // "token" response, the IdP decides that it needs the user to
  // continue on a pop-up window:
  "continue_on": "/oauth/authorize?scope=..."
}

ברגע שהדפדפן מקבל את התגובה continue_on, נפתח חלון קופץ חדש שמנחה את המשתמש לנתיב שצוין.

אחרי שהמשתמש יוצר אינטראקציה עם הדף, למשל, מעניק הרשאה נוספת לשתף מידע נוסף עם ה-RP, דף ה-IdP יכול לבצע קריאה ל-IdentityProvider.resolve() כדי לפתור את הקריאה המקורית ל-navigator.credentials.get() ולהחזיר אסימון כארגומנטים.

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

לאחר מכן הדפדפן ייסגר את חלון הקופץ בעצמו ויחזיר את האסימון למבצע הקריאה ל-API.

אם המשתמש דוחה את הבקשה, אפשר לסגור את החלון באמצעות קריאה ל-IdentityProvider.close().

IdentityProvider.close();

אם מסיבה כלשהי המשתמש שינה את החשבון שלו בחלון הקופץ (לדוגמה, ה-IdP מציע פונקציית 'החלפת משתמש', או במקרים של הענקת גישה), קריאת הפתרון מקבלת ארגומנטים שניים אופציונליים שמאפשרים משהו כמו:

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

Parameters API

ה-API של הפרמטרים מאפשר ל-RP לספק פרמטרים נוספים לנקודת הקצה של טענת הנכונות (assertion) של המזהה. באמצעות Parameters API, גורמים מוגבלים יכולים להעביר פרמטרים נוספים ל-IdP כדי לבקש הרשאות למשאבים מעבר לכניסה הבסיסית. המשתמש יאשר את ההרשאות האלה דרך תהליך UX שנשלט על ידי IdP, שמופעל דרך Continuation API.

כדי להשתמש ב-API, צריך להוסיף פרמטרים למאפיין params כאובייקט בקריאה ל-navigator.credentials.get().

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

שמות המאפיינים באובייקט params מתחילים ב-param_. בדוגמה שלמעלה, המאפיין params מכיל את IDP_SPECIFIC_PARAM בתור '1', את foo בתור 'BAR', את ETC בתור 'MOAR' ואת scope בתור 'calendar.readonly photos.write'. הטקסט הזה יתורגם ל-param_IDP_SPECIFIC_PARAM=1&param_foo=BAR&param_ETC=MOAR&param_scope=calendar.readonly%20photos.write בגוף ה-HTTP של הבקשה:

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

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

אחזור הרשאות באופן דינמי

באופן כללי, מומלץ לבקש מהמשתמשים הרשאות כשהן נחוצות, ולא כשהמפתח חושב שהן הכי פשוטות להטמעה. לדוגמה, עדיף לבקש הרשאה לגשת למצלמה כשהמשתמש עומד לצלם תמונה, ולא לבקש הרשאה ברגע שהוא נכנס לאתר. אותה שיטה חלה גם על משאבי שרת. מבקשים הרשאות רק כשהן נחוצות למשתמש. הפעולה הזו נקראת 'הרשאה דינמית'.

כדי לבקש הרשאה באופן דינמי באמצעות FedCM, ה-IdP יכול:

  1. קוראים ל-navigator.credentials.get() עם הפרמטרים הנדרשים שה-IdP יכול להבין, כמו scope.
  2. נקודת הקצה של טענת הנכוֹנוּת של הזהות מאשרת שהמשתמש כבר נכנס לחשבון ומגיבה עם כתובת URL מסוג continue_on.
  3. הדפדפן יפתח חלון קופץ עם דף ההרשאות של ה-IdP, שבו תתבקשו להעניק הרשאה נוספת שתואמת להיקפים המבוקשים.
  4. לאחר קבלת האישור באמצעות IdentityProvider.resolve() על ידי ה-IdP, החלון נסגר, והקריאה המקורית navigator.credentials.get() של ה-RP מקבלת אסימון רלוונטי או קוד הרשאה כדי שה-RP יוכל להחליף אותו באסימון גישה מתאים.

Fields API

Fields API מאפשר ל-RP להצהיר על מאפייני חשבון לבקש מה-IdP, כדי שהדפדפן יוכל להציג ממשק משתמש מתאים לגילוי נאות בתיבת הדו-שיח של FedCM. האחריות של ה-IdP היא לכלול את השדות המבוקשים בטוקן המוחזר. אפשר להתייחס לבקשה כזו כבקשה ל'פרופיל בסיסי' ב-OpenID Connect, לעומת 'היקפי הרשאות' ב-OAuth.

הודעת גילוי נאות במצב ווידג'ט.
הודעה לגבי גילוי נאות במצב ווידג'ט.
הודעת גילוי נאות במצב לחצן.
הודעה לגבי גילוי נאות במצב לחצן.

כדי להשתמש ב-Fields API, מוסיפים פרמטרים לנכס fields כמערך בקריאה navigator.credentials.get(). בשלב הזה, השדות יכולים להכיל את הערכים 'name',‏ 'email' ו-'picture', אבל בעתיד הם עשויים להתרחב כך שיכללו ערכים נוספים.

בקשה עם fields תיראה כך:

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

בקשת ה-HTTP לנקודת הקצה (endpoint) של הצהרת המזהה כוללת את הפרמטר fields שצוין על ידי ה-RP, כשהפרמטר disclosure_text_shown מוגדר כ-true אם לא מדובר במשתמש חוזר, ואת השדות שהדפדפן גילה למשתמש בפרמטר disclosure_shown_for:

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

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

אם ל-RP יש צורך בגישה לנתונים נוספים מה-IdP, כמו גישה ליומן, צריך לטפל בכך באמצעות פרמטר מותאם אישית כפי שמתואר למעלה. ה-IdP מחזיר כתובת URL מסוג continue_on כדי לבקש הרשאה.

אם fields הוא מערך ריק, הבקשה תיראה כך:

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

אם fields הוא מערך ריק, סוכן המשתמש ידלג על ממשק המשתמש של הגילוי הנאות.

הודעת הגילוי הנאות לא מוצגת במצב ווידג'ט. בתהליך הצגת הלחצן, המערכת מדלגת לגמרי על ממשק המשתמש של הגילוי הנאות.
הודעת הגילוי הנאות לא מוצגת במצב הווידג'ט. בתהליך הלחצן, ממשק המשתמש של גילוי הנאות מושמט לחלוטין.

הדבר נכון גם אם התגובה מנקודת הקצה של החשבונות לא מכילה מזהה לקוח שתואם ל-RP ב-approved_clients.

במקרה הזה, ה-disclosure_text_shown שנשלח לנקודת הקצה של טענת הנכונות (assertion) של המזהה הוא False בגוף ה-HTTP:

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

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

כמה configURLs

כמה configURLs מאפשרים ל-IdPs להכיל כמה קובצי תצורה, על ידי ציון הערכים accounts_endpoint ו-login_url בקובץ ה-well-known, כמו קובצי התצורה.

אם מוסיפים את accounts_endpoint ואת login_url לקובץ הידוע, המערכת מתעלמת מה-provider_urls כדי שה-IdP יוכל לתמוך בכמה קובצי תצורה. אם לא, הערך של provider_urls ימשיך לפעול כדי לשמור על תאימות לאחור.

קובץ ה-well-known שתומך בכמה configURLs יכול להיראות כך:

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

כך אנחנו יכולים:

  1. לשמור על תאימות אחורה וקדימה עם קבצים ידועים קיימים ועם הגרסה הקודמת של הדפדפנים שכבר פרוסים ברחבי העולם.
  2. להשתמש במספר שרירותי של קובצי תצורה, כל עוד כולם מפנים לאותו accounts_endpoint ולאותו login_url.
  3. אין אפשרות להוסיף אנטרופיה לבקשת האחזור עם פרטי הכניסה שנשלחת אל accounts_endpoint, כי צריך לציין אותה ברמה '‎.well-known'.

התמיכה בכמה configURLs היא אופציונלית, וההטמעות הקיימות של FedCM יכולות להישאר ללא שינוי.

תוויות חשבון מותאמות אישית

תוויות חשבון בהתאמה אישית מאפשרות לספקי IdP של FedCM להוסיף הערות לחשבונות, כדי שהגורמים המוגבלים יוכלו לסנן אותם על ידי ציון התווית בקובץ תצורה. אפשרות הסינון דומה באמצעות Domain Hint API ו-Login Hint API על ידי ציון שלהם בקריאה navigator.credentials.get(), אבל התוויות בהתאמה אישית של החשבון יכולות לסנן משתמשים על ידי ציון קובץ התצורה, שמועיל במיוחד כשמשתמשים בכמה כתובות URL של config. תוויות חשבון מותאמות אישית שונות גם בכך שהן מסופקות משרת ה-IdP, בניגוד ל-RP, כמו התחברות או רמזים לדומיין.

דוגמה

IdP תומך בשתי כתובות configURL, אחת לצרכנים ואחת לארגונים. קובץ התצורה של הצרכן כולל את התווית 'consumer', וקובץ התצורה של הארגון מסומן בתווית 'enterprise'.

עם הגדרה כזו, הקובץ הידוע כולל את accounts_endpoint ו-login_url כדי לאפשר מספר כתובות URL של config.

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

כשה-accounts_endpoint מסופק בקובץ ה-well-known, המערכת מתעלמת מה-provider_urls. ה-RP יכול להפנות ישירות לקובצי התצורה המתאימים בקריאה לפעולה navigator.credentials.get().

קובץ התצורה של הצרכן נמצא ב-https://idp.example/fedcm.json, והוא כולל את המאפיין accounts שמציין את 'consumer' באמצעות include.

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

קובץ התצורה הארגוני נמצא בכתובת https://idp.example/enterprise/fedcm.json, והוא כולל את המאפיין accounts שמציין את 'enterprise' באמצעות include.

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

נקודת הקצה (endpoint) המשותפת של IdP (בדוגמה הזו https://idp.example/accounts) מחזירה רשימה של חשבונות שכוללים מאפיין תוויות עם ערך labels שהוקצה במערך לכל חשבון. זוהי דוגמה לתגובה למשתמש שיש לו שני חשבונות. אחד לצרכנים והשני לארגונים:

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

כש-RP רוצה לאפשר למשתמשים ב-'enterprise' להיכנס לחשבון, הוא יכול לציין את 'enterprise' configURL 'https://idp.example/enterprise/fedcm.json' בקריאה navigator.credentials.get():

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

כתוצאה מכך, רק מזהה החשבון '4567' זמין למשתמש כדי להיכנס לחשבון. מזהה החשבון של '123' מוסתר על ידי הדפדפן באופן אוטומטי, כדי שהמשתמש לא יקבל חשבון שלא נתמך על ידי ה-IdP באתר הזה.

גרסת המקור לניסיון: FedCM כאות אמון ל-Storage Access API

דפדפן Chrome 126 מתחיל גרסת מקור לניסיון של FedCM כאות אמון ב-Storage Access API. בעקבות השינוי הזה, הענקת הרשאה מראש דרך FedCM הופכת לסיבה תקפה לאישור אוטומטי של בקשת גישה לאחסון על ידי ממשקי ה-API של גישה לאחסון.

האפשרות הזו שימושית כשמסגרת iframe מוטמעת רוצה לגשת למשאבים מותאמים אישית: לדוגמה, אם idp.example מוטמע ב-rp.example, וצריך להציג משאב מותאם אישית. אם הדפדפן מגביל את הגישה לקובצי cookie של צד שלישי, גם אם המשתמש מחובר ל-rp.example באמצעות idp.example עם FedCM, ה-iframe המוטמע של idp.example לא יוכל לבקש משאבים מותאמים אישית כי הבקשות לא יכללו קובצי cookie של צד שלישי.

כדי לעשות זאת, idp.example צריכה לקבל הרשאת גישה לאחסון דרך ה-iframe שלה שמוטמע באתר. אפשר לקבל את ההרשאה רק באמצעות בקשת הרשאה.

כשמשתמשים ב-FedCM כאות אמון ל-Storage Access API, בדיקות ההרשאות של Storage Access API מקבלות לא רק את הרשאת הגישה שמוענקת בהודעת הבקשה לגישה לאחסון, אלא גם את הרשאת הגישה שמוענקת בהודעת הבקשה של FedCM.

// In top-level rp.example:

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

// In an embedded IdP iframe:

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

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

אחרי שהמשתמש נכנס באמצעות FedCM, ההרשאה ניתנת באופן אוטומטי כל עוד האימות של FedCM פעיל. כלומר, ברגע שהמשתמש מנותק, כשמבקשים הרשאה תוצג הנחיה.

השתתפות בגרסת המקור לניסיון

אפשר לנסות את החבילה של FedCM Continuation API באופן מקומי על ידי הפעלת דגל של Chromechrome://flags#fedcm-authz ב-Chrome 126 ואילך. אפשר גם להפעיל את #fedcm-with-storage-access-api ב-Chrome 126 ואילך כדי לנסות את FedCM כאות אמון ל-Storage Access API באופן מקומי.

התכונות האלה זמינות גם כגרסאות ניסיון למקור. בגרסאות מקור לניסיון אפשר לנסות תכונות חדשות ולתת משוב לגבי נוחות השימוש, המעשיות והיעילות שלהן. מידע נוסף זמין במאמר תחילת העבודה עם ניסויים במקור.

כדי לנסות את גרסת המקור לניסיון של חבילת FedCM Continuation API, צריך ליצור שני אסימונים לניסיון במקור:

אם אתם רוצים להפעיל את Continuation API יחד עם תהליך הלחצן, עליכם להפעיל גם את גרסת המקור לניסיון של Button Mode API:

כדי לנסות את FedCM כאות אמון לגרסת המקור של Storage Access API:

גרסת המקור לניסיון של חבילת Continuation API וה-FedCM כאות אמון בגרסת המקור לניסיון של Storage Access API זמינים ב-Chrome 126.

הרשמה של תקופת ניסיון למקור של צד שלישי ל-RP

  1. עוברים לדף הרישום לגרסת המקור לניסיון.
  2. לוחצים על הלחצן Register וממלאים את הטופס כדי לבקש אסימון.
  3. מזינים את מקור ה-IdP בתור מקור אינטרנט.
  4. בדיקת התאמות של צד שלישי כדי להחדיר את האסימון עם JavaScript במקורות אחרים.
  5. לוחצים על שליחה.
  6. להטמיע את האסימון שהונפק באתר של צד שלישי.

כדי להטמיע את האסימון באתר של צד שלישי, מוסיפים את הקוד הבא לספריית JavaScript או ל-SDK של ה-IdP שמוצגים מהמקור של ה-IdP.

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

מחליפים את TOKEN_GOES_HERE באסימון שלכם.