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

החל מגרסה 126 של Chrome, מפתחים יכולים להתחיל להריץ גרסת מקור לניסיון של חבילת תכונות של Federated Credential Management API (FedCM) שמאפשרות שימוש בתרחישים לדוגמה מסוימים של הרשאה. החבילה כוללת את ממשק ה-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:

ממשק API של המשך

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

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

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

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

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

עם זאת, באמצעות ממשק ה-API של המשך, נקודת הקצה של טענת נכוֹנוּת (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 מציע את הפונקציה "Switch user" (החלפת משתמש), או במקרים של הענקת גישה), הקריאה לסיום הקריאה מקבלת ארגומנט שני אופציונלי, שמאפשר משהו כמו:

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

ממשק API של פרמטרים

ה-API של הפרמטרים מאפשר ל-RP לספק פרמטרים נוספים לנקודת הקצה של טענת הנכונות (assertion) של המזהה. באמצעות Parameters API, גורמים מוגבלים יכולים להעביר פרמטרים נוספים ל-IdP כדי לבקש הרשאות למשאבים מעבר לכניסה הבסיסית. המשתמש יוכל לאשר את ההרשאות האלה באמצעות תהליך חוויית משתמש בשליטת ה-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_. בדוגמה שלמעלה, מאפיין הפרמטרים מכיל את 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. נקודת הקצה (endpoint) של טענת הנכוֹנוּת (assertion) של המזהה מאשרת שהמשתמש כבר מחובר לחשבון, ומגיבה עם כתובת URL מסוג continue_on.
  3. הדפדפן פותח חלון קופץ עם דף ההרשאות של ה-IdP, ומבקש הרשאה נוספת שתואמת להיקפים המבוקשים.
  4. לאחר קבלת האישור דרך IdentityProvider.resolve() על ידי ה-IdP, החלון נסגר, והקריאה המקורית navigator.credentials.get() של ה-RP מקבלת אסימון רלוונטי או קוד הרשאה כדי שה-RP יוכל להחליף אותו באסימון גישה מתאים.

ממשק API של Fields

באמצעות 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

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

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

הקובץ הידוע שתומך בכמה כתובות URL של config יכול להיראות כך:

{
  "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'.

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

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

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

דוגמה

IdP שתומך בשתי כתובות URL config לצרכנים ולארגון, בהתאמה. קובץ התצורה של הצרכן כולל את התווית '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 מצוין בקובץ הידוע, המערכת מתעלמת מה-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 באופן מקומי על ידי הפעלת הדגל של Chrome chrome://flags#fedcm-authz ב-Chrome 126 ואילך. אפשר גם להפעיל את #fedcm-with-storage-access-api ב-Chrome 126 ואילך כדי לנסות את FedCM כאות אמון ל-Storage Access API באופן מקומי.

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

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

אם רוצים להפעיל את Continuation API יחד עם את תהליך הלחצנים, צריך להפעיל גם את גרסת המקור לניסיון של ה-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 באסימון שלכם.