מעבר אל Google Identity Services

סקירה כללית

כדי לקבל אסימון גישה לכל משתמש לקריאה ל-Google APIs, ‏ Google מציעה כמה ספריות JavaScript:

במדריך הזה מוסבר איך לבצע מיגרציה מהספריות האלה אל הספרייה של Google Identity Services.

במדריך הזה תלמדו:

  • להחליף את ספריית הפלטפורמה שהוצאה משימוש בספריית Identity Services, ו
  • אם משתמשים בספריית הלקוח של ה-API, צריך להסיר את מודול gapi.auth2 שהוצא משימוש, את השיטות והאובייקטים שלו, ולהחליף אותם באובייקטים מקבילים של שירותי הזהויות.

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

אם אתם מחפשים אימות לצורך הרשמה וכניסה של משתמשים, כדאי לעיין במאמר בנושא מעבר מ'כניסה באמצעות חשבון Google'.

זיהוי תהליך ההרשאה

יש שני תהליכי הרשאה אפשריים למשתמשים: הרשאה מרומזת והרשאת קוד.

בודקים את אפליקציית האינטרנט כדי לזהות את סוג תהליך ההרשאה שבו נעשה שימוש.

סימנים לכך שאפליקציית האינטרנט משתמשת בתהליך הרשאה מרומז:

  • אפליקציית האינטרנט שלך מבוססת על דפדפן בלבד, ללא פלטפורמת קצה עורפי.
  • המשתמש צריך להיות נוכח כדי להתקשר אל Google APIs, האפליקציה משתמשת רק בטוקנים של גישה, ולא נדרשים טוקנים של רענון.
  • אפליקציית האינטרנט נטענת apis.google.com/js/api.js.
  • ההטמעה שלכם מבוססת על OAuth 2.0 לאפליקציות אינטרנט בצד הלקוח.
  • האפליקציה שלך משתמשת במודולים gapi.client או gapi.auth2 שנמצאים בספריית הלקוח של Google API ל-JavaScript.

סימנים לכך שאפליקציית האינטרנט משתמשת בהרשאה באמצעות קוד:

במקרים מסוימים, בסיס הקוד שלכם עשוי לתמוך בשני התהליכים.

בחירת תהליך הרשאה

לפני שמתחילים את ההעברה, צריך להחליט אם להמשיך עם התהליך הקיים או לעבור לתהליך אחר שמתאים יותר לצרכים שלכם.

כדאי לעיין במאמר בנושא בחירת תהליך הרשאה כדי להבין את ההבדלים העיקריים בין שני התהליכים ואת היתרונות והחסרונות של כל אחד מהם.

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

בוחרים תהליך הרשאה באמצעות התפריטים הנפתחים.

זרם הענקת גישה משתמע

קבלת טוקן גישה לשימוש בדפדפן בזמן שהמשתמש נמצא.

דוגמאות לזרימה משתמעת מציגות אפליקציות אינטרנט לפני ואחרי ההעברה אל שירותי זהויות.

הרשאה באמצעות קוד

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

בדוגמאות לזרימת הרשאה באמצעות קוד מוצגות אפליקציות אינטרנט לפני ואחרי המעבר לשירותי זהויות.

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

שינויים באפליקציית האינטרנט בדפדפן

בקטע הזה מוסבר על השינויים שתצטרכו לבצע באפליקציית האינטרנט שלכם בדפדפן כשאתם עוברים לספריית JavaScript של Google Identity Services.

זיהוי הקוד המושפע ובדיקה

קובץ Cookie לניפוי באגים יכול לעזור לכם לאתר את הקוד המושפע ולבדוק את ההתנהגות אחרי ההוצאה משימוש.

באפליקציות גדולות או מורכבות, יכול להיות שיהיה קשה למצוא את כל הקוד שמושפע מהוצאה משימוש של מודול gapi.auth2. כדי לרשום ביומן את השימוש הקיים בפונקציונליות שעומדת לצאת משימוש במסוף, צריך להגדיר את הערך של קובץ ה-Cookie‏ G_AUTH2_MIGRATION ל-informational. אופציונלי: מוסיפים נקודתיים ואחריהן ערך מפתח כדי לרשום את הנתונים גם באחסון הסשן. אחרי הכניסה לחשבון וקבלת אישור על פרטי הכניסה, או לשלוח יומנים שנאספו לשרת עורפי לצורך ניתוח מאוחר יותר. לדוגמה, הפקודה informational:showauth2use שומרת את המקור ואת כתובת ה-URL במפתח של אחסון סשן בשם showauth2use.

כדי לוודא את התנהגות האפליקציה כשמודול gapi.auth2 לא נטען יותר, צריך להגדיר את הערך של קובץ ה-cookie G_AUTH2_MIGRATION ל-enforced. כך אפשר לבדוק את ההתנהגות של המערכת אחרי ההוצאה משימוש לפני תאריך האכיפה.

ערכים אפשריים של קובצי Cookie‏ G_AUTH2_MIGRATION:

  • enforced אל תטען את המודול gapi.auth2.
  • informational רישום השימוש בפונקציות שהוצאו משימוש במסוף JavaScript. גם מתבצעת כניסה לאחסון הסשן כשמוגדר שם מפתח אופציונלי: informational:key-name.

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

ספריות ומודולים

מודול gapi.auth2 מנהל את אימות המשתמשים לצורך כניסה ואת התהליך המרומז להרשאה. צריך להחליף את המודול הזה שהוצא משימוש, ואת האובייקטים והשיטות שלו בספרייה של Google Identity Services.

מוסיפים את ספריית Identity Services לאפליקציית האינטרנט על ידי הכללתה במסמך:

<script src="https://accounts.google.com/gsi/client" async defer></script>

מסירים את כל המקרים של טעינת המודול auth2 באמצעות gapi.load('auth2', function).

הספרייה של Google Identity Services מחליפה את השימוש במודול gapi.auth2. אפשר להמשיך להשתמש בבטחה במודול gapi.client מתוך ספריית הלקוח של Google API ל-JavaScript, וליהנות מהיכולת שלו ליצור באופן אוטומטי שיטות JS שאפשר להפעיל ממסמך גילוי, לאגד כמה קריאות ל-API ולנהל את ה-CORS.

קובצי Cookie

הרשאת משתמש לא מחייבת שימוש בקובצי Cookie.

במאמר מעבר מ-Google Sign-In מוסבר איך קובצי Cookie משמשים לאימות משתמשים, ובמאמר איך Google משתמשת בקובצי Cookie מוסבר איך קובצי Cookie משמשים במוצרים ובשירותים אחרים של Google.

פרטי כניסה

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

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

זרם הענקת גישה משתמע

הפרדה בין אימות משתמשים לבין הרשאות גישה על ידי הסרת הטיפול בפרופיל המשתמש מתהליכי ההרשאה.

מסירים את הפניות האלה ללקוח JavaScript של הכניסה באמצעות חשבון Google:

Methods

  • GoogleUser.getBasicProfile()
  • GoogleUser.getId()

הרשאה באמצעות קוד

שירותי הזהויות מפרידים את פרטי הכניסה בדפדפן לאסימון מזהה ולאסימון גישה. השינוי הזה לא חל על פרטי כניסה שהתקבלו באמצעות קריאות ישירות לנקודות הקצה של Google OAuth 2.0 מפלטפורמת ה-Backend שלכם, או באמצעות ספריות שפועלות בשרת מאובטח בפלטפורמה שלכם, כמו Google APIs Node.js Client.

מצב הסשן

בעבר, התכונה 'כניסה באמצעות חשבון Google' עזרה לכם לנהל את סטטוס הכניסה של המשתמשים באמצעות:

אתם אחראים לניהול מצב הכניסה והסשנים של המשתמשים באפליקציית האינטרנט שלכם.

מסירים את הפניות האלה ללקוח JavaScript של הכניסה באמצעות חשבון Google:

אובייקטים:

  • gapi.auth2.SignInOptions

שיטות:

  • GoogleAuth.attachClickHandler()
  • GoogleAuth.isSignedIn()
  • GoogleAuth.isSignedIn.get()
  • GoogleAuth.isSignedIn.listen()
  • GoogleAuth.signIn()
  • GoogleAuth.signOut()
  • GoogleAuth.currentUser.get()
  • GoogleAuth.currentUser.listen()
  • GoogleUser.isSignedIn()

הגדרת לקוח

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

מסירים את הפניות האלה ללקוח JavaScript של הכניסה באמצעות חשבון Google:

אובייקטים:

  • gapi.auth2.ClientConfig
  • gapi.auth2.OfflineAccessOptions

שיטות:

  • gapi.auth2.getAuthInstance()
  • GoogleUser.grant()

זרם הענקת גישה משתמע

מוסיפים אובייקט TokenClientConfig וקריאה ל-initTokenClient() כדי להגדיר את אפליקציית האינטרנט, לפי הדוגמה שבמאמר איך מאתחלים לקוח של טוקן.

החלפה של הפניות ללקוח JavaScript של הכניסה לחשבון Google בGoogle Identity Services:

אובייקטים:

  • gapi.auth2.AuthorizeConfig עם TokenClientConfig

שיטות:

  • gapi.auth2.init() עם google.accounts.oauth2.initTokenClient()

פרמטרים:

  • gapi.auth2.AuthorizeConfig.login_hint עם TokenClientConfig.login_hint.
  • gapi.auth2.GoogleUser.getHostedDomain() עם TokenClientConfig.hd.

הרשאה באמצעות קוד

מוסיפים אובייקט CodeClientConfig וקריאה ל-initCodeClient() כדי להגדיר את אפליקציית האינטרנט, לפי הדוגמה שבמאמר איך מאתחלים לקוח קוד.

כשעוברים מהרשאה מרומזת להרשאה באמצעות קוד:

הסרת הפניות ללקוח JavaScript של כניסה באמצעות חשבון Google

אובייקטים:

  • gapi.auth2.AuthorizeConfig

שיטות:

  • gapi.auth2.init()

פרמטרים:

  • gapi.auth2.AuthorizeConfig.login_hint
  • gapi.auth2.GoogleUser.getHostedDomain()

בקשה לטוקן

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

זרם הענקת גישה משתמע

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

החלפה של הפניות ללקוח JavaScript של 'כניסה באמצעות חשבון Google': בGoogle Identity Services:

שיטות:

  • gapi.auth2.authorize() עם TokenClient.requestAccessToken()
  • GoogleUser.reloadAuthResponse() עם TokenClient.requestAccessToken()

מוסיפים קישור או לחצן להתקשרות עם requestAccessToken() כדי להתחיל את תהליך חוויית המשתמש של חלון קופץ לבקשת אסימון גישה, או כדי לקבל אסימון חדש כשהאסימון הקיים פג.

מעדכנים את בסיס הקוד כך שיכלול:

  • מפעילים את תהליך אסימון OAuth 2.0 באמצעות requestAccessToken().
  • תמיכה בהרשאה מצטברת באמצעות requestAccessToken ו-OverridableTokenClientConfig כדי לפצל בקשה אחת עם הרבה היקפי הרשאה לכמה בקשות קטנות יותר.
  • לבקש טוקן חדש כשהתוקף של הטוקן הקיים פג או כשהוא בוטל.

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

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

הרשאה באמצעות קוד

מוסיפים קישור או לחצן להתקשרות אל requestCode() כדי לבקש קוד הרשאה מ-Google. לדוגמה, אפשר לעיין במאמר הפעלת תהליך קוד OAuth 2.0.

בקטע 'טיפול בטוקנים' מוסבר איך להגיב לטוקן גישה שפג תוקפו או שבוטל.

טיפול בטוקנים

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

קודי הסטטוס של HTTP‏ 401 Unauthorized והודעת השגיאה invalid_token מוחזרים מממשקי ה-API של Google כשמשתמשים בטוקן גישה שפג תוקפו או שבוטל. דוגמה מופיעה במאמר תגובה לא תקינה של אסימון.

אסימונים שפג תוקפם

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

ביטול טוקן

בכל שלב, הבעלים של חשבון Google יכול לבטל הסכמה שניתנה בעבר. פעולה כזו מבטלת את התוקף של אסימוני גישה ואסימוני רענון קיימים. יכול להיות שהביטול יופעל מהפלטפורמה שלכם באמצעות revoke() או דרך חשבון Google.

החלפה של הפניות ללקוח JavaScript של 'כניסה באמצעות חשבון Google': בGoogle Identity Services:

שיטות:

  • getAuthInstance().disconnect() עם google.accounts.oauth2.revoke()
  • GoogleUser.disconnect() עם google.accounts.oauth2.revoke()

צריך להתקשר אל revoke כשמשתמש מוחק את החשבון שלו בפלטפורמה שלכם, או כשהוא רוצה לבטל את ההסכמה שלו לשיתוף נתונים עם האפליקציה שלכם.

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

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

כניסה של משתמשים

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

  • מצמצם את מספר הפעמים שמשתמש צריך להיכנס לחשבון. אם לא קיים סשן פעיל, בקשה לטוקן גישה מפעילה את תהליך הכניסה לחשבון Google.
  • משתמשים ישירות בשדה credential email של אסימון מזהה JWT כערך של הפרמטר login_hint באובייקטים CodeClientConfig או TokenClientConfig. האפשרות הזו שימושית במיוחד אם בפלטפורמה שלכם אין מערכת לניהול חשבונות משתמשים.
  • חיפוש חשבון Google ושיוכו לחשבון משתמש מקומי קיים בפלטפורמה שלכם, כדי לצמצם את מספר החשבונות הכפולים בפלטפורמה.
  • כשיוצרים חשבון מקומי חדש, אפשר להפריד בבירור בין תיבות הדו-שיח ותהליך ההרשמה לבין תיבות הדו-שיח ותהליך האימות של המשתמשים. כך אפשר לצמצם את מספר השלבים הנדרשים ולשפר את שיעור הנטישה.

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

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

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

זרם הענקת גישה משתמע

החלפה של הפניות ללקוח JavaScript של הכניסה לחשבון Google בGoogle Identity Services:

אובייקטים:

  • gapi.auth2.AuthorizeResponse עם TokenClient.TokenResponse
  • gapi.auth2.AuthResponse עם TokenClient.TokenResponse

שיטות:

  • GoogleUser.hasGrantedScopes() עם google.accounts.oauth2.hasGrantedAllScopes()
  • GoogleUser.getGrantedScopes() עם google.accounts.oauth2.hasGrantedAllScopes()

הסרת הפניות ללקוח JavaScript של 'כניסה באמצעות חשבון Google':

שיטות:

  • GoogleUser.getAuthResponse()

מעדכנים את אפליקציית האינטרנט באמצעות hasGrantedAllScopes() ו-hasGrantedAnyScope() לפי הדוגמה הזו של הרשאות גרנולריות.

הרשאה באמצעות קוד

מעדכנים או מוסיפים נקודת קצה של קוד הרשאה לפלטפורמת ה-Backend באמצעות ההוראות שבקטע טיפול בקוד הרשאה.

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

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

דוגמאות לזרם הענקת גישה משתמע

הדרך הישנה

ספריית לקוח GAPI

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

המודול gapi.auth2 נטען אוטומטית ומשמש את gapi.client.init(), ולכן הוא מוסתר.

<!DOCTYPE html>
  <html>
    <head>
      <script src="https://apis.google.com/js/api.js"></script>
      <script>
        function start() {
          gapi.client.init({
            'apiKey': 'YOUR_API_KEY',
            'clientId': 'YOUR_CLIENT_ID',
            'scope': 'https://www.googleapis.com/auth/cloud-translation',
            'discoveryDocs': ['https://www.googleapis.com/discovery/v1/apis/translate/v2/rest'],
          }).then(function() {
            // Execute an API request which is returned as a Promise.
            // The method name language.translations.list comes from the API discovery.
            return gapi.client.language.translations.list({
              q: 'hello world',
              source: 'en',
              target: 'de',
            });
          }).then(function(response) {
            console.log(response.result.data.translations[0].translatedText);
          }, function(reason) {
            console.log('Error: ' + reason.result.error.message);
          });
        };

        // Load the JavaScript client library and invoke start afterwards.
        gapi.load('client', start);
      </script>
    </head>
    <body>
      <div id="results"></div>
    </body>
  </html>

ספריית לקוח JS

OAuth 2.0 לאפליקציות אינטרנט בצד הלקוח שפועלות בדפדפן באמצעות תיבת דו-שיח קופצת לבקשת הסכמת המשתמש.

מודול gapi.auth2 נטען באופן ידני.

<!DOCTYPE html>
<html><head></head><body>
<script>
  var GoogleAuth;
  var SCOPE = 'https://www.googleapis.com/auth/drive.metadata.readonly';
  function handleClientLoad() {
    // Load the API's client and auth2 modules.
    // Call the initClient function after the modules load.
    gapi.load('client:auth2', initClient);
  }

  function initClient() {
    // In practice, your app can retrieve one or more discovery documents.
    var discoveryUrl = 'https://www.googleapis.com/discovery/v1/apis/drive/v3/rest';

    // Initialize the gapi.client object, which app uses to make API requests.
    // Get API key and client ID from Google Cloud console.
    // 'scope' field specifies space-delimited list of access scopes.
    gapi.client.init({
        'apiKey': 'YOUR_API_KEY',
        'clientId': 'YOUR_CLIENT_ID',
        'discoveryDocs': [discoveryUrl],
        'scope': SCOPE
    }).then(function () {
      GoogleAuth = gapi.auth2.getAuthInstance();

      // Listen for sign-in state changes.
      GoogleAuth.isSignedIn.listen(updateSigninStatus);

      // Handle initial sign-in state. (Determine if user is already signed in.)
      var user = GoogleAuth.currentUser.get();
      setSigninStatus();

      // Call handleAuthClick function when user clicks on
      //      "Sign In/Authorize" button.
      $('#sign-in-or-out-button').click(function() {
        handleAuthClick();
      });
      $('#revoke-access-button').click(function() {
        revokeAccess();
      });
    });
  }

  function handleAuthClick() {
    if (GoogleAuth.isSignedIn.get()) {
      // User is authorized and has clicked "Sign out" button.
      GoogleAuth.signOut();
    } else {
      // User is not signed in. Start Google auth flow.
      GoogleAuth.signIn();
    }
  }

  function revokeAccess() {
    GoogleAuth.disconnect();
  }

  function setSigninStatus() {
    var user = GoogleAuth.currentUser.get();
    var isAuthorized = user.hasGrantedScopes(SCOPE);
    if (isAuthorized) {
      $('#sign-in-or-out-button').html('Sign out');
      $('#revoke-access-button').css('display', 'inline-block');
      $('#auth-status').html('You are currently signed in and have granted ' +
          'access to this app.');
    } else {
      $('#sign-in-or-out-button').html('Sign In/Authorize');
      $('#revoke-access-button').css('display', 'none');
      $('#auth-status').html('You have not authorized this app or you are ' +
          'signed out.');
    }
  }

  function updateSigninStatus() {
    setSigninStatus();
  }
</script>

<button id="sign-in-or-out-button"
        style="margin-left: 25px">Sign In/Authorize</button>
<button id="revoke-access-button"
        style="display: none; margin-left: 25px">Revoke access</button>

<div id="auth-status" style="display: inline; padding-left: 25px"></div><hr>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script async defer src="https://apis.google.com/js/api.js"
        onload="this.onload=function(){};handleClientLoad()"
        onreadystatechange="if (this.readyState === 'complete') this.onload()">
</script>
</body></html>

נקודות קצה של OAuth 2.0

OAuth 2.0 לאפליקציות אינטרנט בצד הלקוח שפועלות בדפדפן באמצעות הפניות אוטומטיות אל Google לקבלת הסכמת המשתמש.

בדוגמה הזו מוצגות קריאות ישירות לנקודות הקצה של Google OAuth 2.0 מדפדפן המשתמש, בלי שימוש במודול gapi.auth2 או בספריית JavaScript.

<!DOCTYPE html>
<html><head></head><body>
<script>
  var YOUR_CLIENT_ID = 'REPLACE_THIS_VALUE';
  var YOUR_REDIRECT_URI = 'REPLACE_THIS_VALUE';
  var fragmentString = location.hash.substring(1);

  // Parse query string to see if page request is coming from OAuth 2.0 server.
  var params = {};
  var regex = /([^&=]+)=([^&]*)/g, m;
  while (m = regex.exec(fragmentString)) {
    params[decodeURIComponent(m[1])] = decodeURIComponent(m[2]);
  }
  if (Object.keys(params).length > 0) {
    localStorage.setItem('oauth2-test-params', JSON.stringify(params) );
    if (params['state'] && params['state'] == 'try_sample_request') {
      trySampleRequest();
    }
  }

  // If there's an access token, try an API request.
  // Otherwise, start OAuth 2.0 flow.
  function trySampleRequest() {
    var params = JSON.parse(localStorage.getItem('oauth2-test-params'));
    if (params && params['access_token']) {
      var xhr = new XMLHttpRequest();
      xhr.open('GET',
          'https://www.googleapis.com/drive/v3/about?fields=user&' +
          'access_token=' + params['access_token']);
      xhr.onreadystatechange = function (e) {
        if (xhr.readyState === 4 && xhr.status === 200) {
          console.log(xhr.response);
        } else if (xhr.readyState === 4 && xhr.status === 401) {
          // Token invalid, so prompt for user permission.
          oauth2SignIn();
        }
      };
      xhr.send(null);
    } else {
      oauth2SignIn();
    }
  }

  /*

    *   Create form to request access token from Google's OAuth 2.0 server.
 */
function oauth2SignIn() {
  // Google's OAuth 2.0 endpoint for requesting an access token
  var oauth2Endpoint = 'https://accounts.google.com/o/oauth2/v2/auth';

    // Create element to open OAuth 2.0 endpoint in new window.
    var form = document.createElement('form');
    form.setAttribute('method', 'GET'); // Send as a GET request.
    form.setAttribute('action', oauth2Endpoint);

    // Parameters to pass to OAuth 2.0 endpoint.
    var params = {'client_id': YOUR_CLIENT_ID,
                  'redirect_uri': YOUR_REDIRECT_URI,
                  'scope': 'https://www.googleapis.com/auth/drive.metadata.readonly',
                  'state': 'try_sample_request',
                  'include_granted_scopes': 'true',
                  'response_type': 'token'};

    // Add form parameters as hidden input values.
    for (var p in params) {
      var input = document.createElement('input');
      input.setAttribute('type', 'hidden');
      input.setAttribute('name', p);
      input.setAttribute('value', params[p]);
      form.appendChild(input);
    }

    // Add form to page and submit it to open the OAuth 2.0 endpoint.
    document.body.appendChild(form);
    form.submit();
  }
</script>

<button onclick="trySampleRequest();">Try sample request</button>
</body></html>

הדרך החדשה

GIS בלבד

בדוגמה הזו מוצגת רק ספריית JavaScript של Google Identity Service שמשתמשת במודל האסימונים ובתיבת דו-שיח קופצת להבעת הסכמה של המשתמש. הוא נועד להמחיש את המספר המינימלי של השלבים שנדרשים כדי להגדיר לקוח, לבקש ולקבל אסימון גישה ולקרוא ל-Google API.

<!DOCTYPE html>
<html>
  <head>
    <script src="https://accounts.google.com/gsi/client" onload="initClient()" async defer></script>
  </head>
  <body>
    <script>
      var client;
      var access_token;

      function initClient() {
        client = google.accounts.oauth2.initTokenClient({
          client_id: 'YOUR_CLIENT_ID',
          scope: 'https://www.googleapis.com/auth/calendar.readonly \
                  https://www.googleapis.com/auth/contacts.readonly',
          callback: (tokenResponse) => {
            access_token = tokenResponse.access_token;
          },
        });
      }
      function getToken() {
        client.requestAccessToken();
      }
      function revokeToken() {
        google.accounts.oauth2.revoke(access_token, () => {console.log('access token revoked')});
      }
      function loadCalendar() {
        var xhr = new XMLHttpRequest();
        xhr.open('GET', 'https://www.googleapis.com/calendar/v3/calendars/primary/events');
        xhr.setRequestHeader('Authorization', 'Bearer ' + access_token);
        xhr.send();
      }
    </script>
    <h1>Google Identity Services Authorization Token model</h1>
    <button onclick="getToken();">Get access token</button><br><br>
    <button onclick="loadCalendar();">Load Calendar</button><br><br>
    <button onclick="revokeToken();">Revoke token</button>
  </body>
</html>

GAPI async/await

בדוגמה הזו מוצגות הפעולות הבאות: הוספה של ספריית Google Identity Service באמצעות מודל האסימונים, הסרה של מודול gapi.auth2 וקריאה ל-API באמצעות Google API Client Library for JavaScript.

הפונקציות Promises,‏ async ו-await משמשות לאכיפת סדר הטעינה של הספרייה, ולזיהוי שגיאות הרשאה וניסיון חוזר לתיקון שלהן. קריאה ל-API מתבצעת רק אחרי שאסימון גישה תקין זמין.

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

<!DOCTYPE html>
<html>
<head>
    <title>GAPI and GIS Example</title>
    <script async defer src="https://apis.google.com/js/api.js" onload="gapiLoad()"></script>
    <script async defer src="https://accounts.google.com/gsi/client" onload="gisLoad()"></script>
</head>
<body>
    <h1>GAPI Client with GIS Authorization</h1>
    <button id="authorizeBtn" style="visibility:hidden;">Authorize and Load Events</button>
    <button id="revokeBtn" style="visibility:hidden;">Revoke Access</button>
    <div id="content"></div>

    <script>
        const YOUR_CLIENT_ID = "YOUR_CLIENT_ID";
        const YOUR_API_KEY = 'YOUR_API_KEY';
        const CALENDAR_SCOPE = 'https://www.googleapis.com/auth/calendar.readonly';

        let tokenClient;
        let libsLoaded = 0;

        function gapiLoad() {
            gapi.load('client', initGapiClient);
        }

        async function initGapiClient() {
            try {
                await gapi.client.init({ apiKey: YOUR_API_KEY });
                await gapi.client.load('https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest');
                console.log('GAPI client initialized.');
                checkAllLoaded();
            } catch (err) {
                handleError('GAPI initialization failed:', err);
            }
        }

        function gisLoad() {
            try {
                tokenClient = google.accounts.oauth2.initTokenClient({
                    client_id: YOUR_CLIENT_ID,
                    scope: CALENDAR_SCOPE,
                    callback: '', // Will be set dynamically
                    error_callback: handleGisError,
                });
                console.log('GIS TokenClient initialized.');
                checkAllLoaded();
            } catch (err) {
                handleError('GIS initialization failed:', err);
            }
        }

        function checkAllLoaded() {
            libsLoaded++;
            if (libsLoaded === 2) {
                document.getElementById('authorizeBtn').style.visibility = 'visible';
                document.getElementById('revokeBtn').style.visibility = 'visible';
                document.getElementById('authorizeBtn').onclick = makeApiCall;
                document.getElementById('revokeBtn').onclick = revokeAccess;
                console.log('Ready to authorize.');
            }
        }

        function handleGisError(err) {
            console.error('GIS Error:', err);
            let message = 'An error occurred during authorization.';
            if (err && err.type === 'popup_failed_to_open') {
                message = 'Failed to open popup. Please disable popup blockers.';
            } else if (err && err.type === 'popup_closed') {
                message = 'Authorization popup was closed.';
            }
            document.getElementById('content').textContent = message;
        }

        function handleError(message, error) {
            console.error(message, error);
            document.getElementById('content').textContent = `${message} ${error.message || JSON.stringify(error)}`;
        }

        async function makeApiCall() {
            document.getElementById('content').textContent = 'Processing...';
            try {
                let token = gapi.client.getToken();
                if (!token || !token.access_token) {
                    console.log('No token, fetching one...');
                    await getToken();
                }

                console.log('Calling Calendar API...');
                const response = await gapi.client.calendar.events.list({ 'calendarId': 'primary' });
                displayEvents(response.result);
            } catch (err) {
                console.error('API call failed:', err);
                const errorInfo = err.result && err.result.error;
                if (errorInfo && (errorInfo.code === 401 || (errorInfo.code === 403 && errorInfo.status === "PERMISSION_DENIED"))) {
                    console.log('Auth error on API call, refreshing token...');
                    try {
                        await getToken({ prompt: 'consent' }); // Force refresh
                        const retryResponse = await gapi.client.calendar.events.list({ 'calendarId': 'primary' });
                        displayEvents(retryResponse.result);
                    } catch (refreshErr) {
                        handleError('Failed to refresh token or retry API call:', refreshErr);
                    }
                } else {
                    handleError('Error loading events:', err.result ? err.result.error : err);
                }
            }
        }

        async function getToken(options = { prompt: '' }) {
            return new Promise((resolve, reject) => {
                if (!tokenClient) return reject(new Error("GIS TokenClient not initialized."));
                tokenClient.callback = (tokenResponse) => {
                    if (tokenResponse.error) {
                        reject(new Error(`Token Error: ${tokenResponse.error} - ${tokenResponse.error_description}`));
                    } else {
                        console.log('Token acquired.');
                        resolve(tokenResponse);
                    }
                };
                tokenClient.requestAccessToken(options);
            });
        }

        function displayEvents(result) {
            const events = result.items;
            if (events && events.length > 0) {
                let eventList = '<h3>Upcoming Events:</h3><ul>' + events.map(event =>
                    `<li>${event.summary} (${event.start.dateTime || event.start.date})</li>`
                ).join('') + '</ul>';
                document.getElementById('content').innerHTML = eventList;
            } else {
                document.getElementById('content').textContent = 'No upcoming events found.';
            }
        }

        function revokeAccess() {
            const token = gapi.client.getToken();
            if (token && token.access_token) {
                google.accounts.oauth2.revoke(token.access_token, () => {
                    console.log('Access revoked.');
                    document.getElementById('content').textContent = 'Access has been revoked.';
                    gapi.client.setToken(null);
                });
            } else {
                document.getElementById('content').textContent = 'No token to revoke.';
            }
        }
    </script>
</body>
</html>

קריאה חוזרת (callback) של GAPI

בדוגמה הזו מוצגות הפעולות הבאות: הוספה של ספריית Google Identity Service באמצעות מודל האסימונים, הסרה של מודול gapi.auth2 וקריאה ל-API באמצעות Google API Client Library for JavaScript.

המשתנים משמשים לאכיפת סדר הטעינה של הספריות. קריאות GAPI מתבצעות מתוך הקריאה החוזרת (callback) אחרי שאסימון גישה תקין מוחזר.

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

<!DOCTYPE html>
<html>
<head>
  <script async defer src="https://apis.google.com/js/api.js" onload="gapiLoad()"></script>
  <script async defer src="https://accounts.google.com/gsi/client" onload="gisInit()"></script>
</head>
<body>
  <h1>GAPI with GIS callbacks</h1>
  <button id="showEventsBtn" onclick="showEvents();">Show Calendar</button><br><br>
  <button id="revokeBtn" onclick="revokeToken();">Revoke access token</button>
  <script>
    let tokenClient;
    let gapiInited;
    let gisInited;

    document.getElementById("showEventsBtn").style.visibility="hidden";
    document.getElementById("revokeBtn").style.visibility="hidden";

    function checkBeforeStart() {
       if (gapiInited && gisInited){
          // Start only when both gapi and gis are initialized.
          document.getElementById("showEventsBtn").style.visibility="visible";
          document.getElementById("revokeBtn").style.visibility="visible";
       }
    }

    function gapiInit() {
      gapi.client.init({
        // NOTE: OAuth2 'scope' and 'client_id' parameters have moved to initTokenClient().
      })
      .then(function() {  // Load the Calendar API discovery document.
        gapi.client.load('https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest');
        gapiInited = true;
        checkBeforeStart();
      });
    }

    function gapiLoad() {
        gapi.load('client', gapiInit)
    }

    function gisInit() {
     tokenClient = google.accounts.oauth2.initTokenClient({
                client_id: 'YOUR_CLIENT_ID',
                scope: 'https://www.googleapis.com/auth/calendar.readonly',
                callback: '',  // defined at request time
            });
      gisInited = true;
      checkBeforeStart();
    }

    function showEvents() {

      tokenClient.callback = (resp) => {
        if (resp.error !== undefined) {
          throw(resp);
        }
        // GIS has automatically updated gapi.client with the newly issued access token.
        console.log('gapi.client access token: ' + JSON.stringify(gapi.client.getToken()));

        gapi.client.calendar.events.list({ 'calendarId': 'primary' })
        .then(calendarAPIResponse => console.log(JSON.stringify(calendarAPIResponse)))
        .catch(err => console.log(err));

        document.getElementById("showEventsBtn").innerText = "Refresh Calendar";
      }

      // Conditionally ask users to select the Google Account they'd like to use,
      // and explicitly obtain their consent to fetch their Calendar.
      // NOTE: To request an access token a user gesture is necessary.
      if (gapi.client.getToken() === null) {
        // Prompt the user to select a Google Account and asked for consent to share their data
        // when establishing a new session.
        tokenClient.requestAccessToken({prompt: 'consent'});
      } else {
        // Skip display of account chooser and consent dialog for an existing session.
        tokenClient.requestAccessToken({prompt: ''});
      }
    }

    function revokeToken() {
      let cred = gapi.client.getToken();
      if (cred !== null) {
        google.accounts.oauth2.revoke(cred.access_token, () => {console.log('Revoked: ' + cred.access_token)});
        gapi.client.setToken('');
        document.getElementById("showEventsBtn").innerText = "Show Calendar";
      }
    }
  </script>
</body>
</html>

דוגמאות להרשאה באמצעות קוד

ממשק המשתמש של חלון קופץ בספריית Google Identity Services יכול להשתמש בהפניה אוטומטית של כתובת URL כדי להחזיר קוד הרשאה ישירות לנקודת הקצה של ה-token בעורף האתר, או במטפל של קריאה חוזרת (callback) של JavaScript שפועל בדפדפן של המשתמש ומעביר את התגובה לפלטפורמה. בכל מקרה, פלטפורמת ה-Backend שלכם תשלים את תהליך OAuth 2.0 כדי לקבל טוקן רענון וטוקן גישה תקינים.

הדרך הישנה

אפליקציות אינטרנט בצד השרת

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

<!DOCTYPE html>
<html>
  <head>
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
    <script src="https://apis.google.com/js/client:platform.js?onload=start" async defer></script>
    <script>
      function start() {
        gapi.load('auth2', function() {
          auth2 = gapi.auth2.init({
            client_id: 'YOUR_CLIENT_ID',
            api_key: 'YOUR_API_KEY',
            discovery_docs: ['https://www.googleapis.com/discovery/v1/apis/translate/v2/rest'],
            // Scopes to request in addition to 'profile' and 'email'
            scope: 'https://www.googleapis.com/auth/cloud-translation',
          });
        });
      }
      function signInCallback(authResult) {
        if (authResult['code']) {
          console.log("sending AJAX request");
          // Send authorization code obtained from Google to backend platform
          $.ajax({
            type: 'POST',
            url: 'YOUR_AUTHORIZATION_CODE_ENDPOINT_URL',
            // Always include an X-Requested-With header to protect against CSRF attacks.
            headers: {
              'X-Requested-With': 'XMLHttpRequest'
            },
            contentType: 'application/octet-stream; charset=utf-8',
            success: function(result) {
              console.log(result);
            },
            processData: false,
            data: authResult['code']
          });
        } else {
          console.log('error: failed to obtain authorization code')
        }
      }
    </script>
  </head>
  <body>
    <button id="signinButton">Sign In With Google</button>
    <script>
      $('#signinButton').click(function() {
        // Obtain an authorization code from Google
        auth2.grantOfflineAccess().then(signInCallback);
      });
    </script>
  </body>
</html>

‫HTTP/REST באמצעות הפניה אוטומטית

שימוש ב-OAuth 2.0 לאפליקציות של שרת אינטרנט כדי לשלוח קוד הרשאה מדפדפן המשתמש לפלטפורמת הקצה העורפי שלכם. הסכמת המשתמשים מטופלת על ידי הפניית הדפדפן של המשתמש אל Google.

/\*
 \* Create form to request access token from Google's OAuth 2.0 server.
 \*/
function oauthSignIn() {
  // Google's OAuth 2.0 endpoint for requesting an access token
  var oauth2Endpoint = 'https://accounts.google.com/o/oauth2/v2/auth';
  // Create &lt;form> element to submit parameters to OAuth 2.0 endpoint.
  var form = document.createElement('form');
  form.setAttribute('method', 'GET'); // Send as a GET request.
  form.setAttribute('action', oauth2Endpoint);
  // Parameters to pass to OAuth 2.0 endpoint.
  var params = {'client\_id': 'YOUR_CLIENT_ID',
                'redirect\_uri': 'YOUR_AUTHORIZATION_CODE_ENDPOINT_URL',
                'response\_type': 'token',
                'scope': 'https://www.googleapis.com/auth/drive.metadata.readonly',
                'include\_granted\_scopes': 'true',
                'state': 'pass-through value'};
  // Add form parameters as hidden input values.
  for (var p in params) {
    var input = document.createElement('input');
    input.setAttribute('type', 'hidden');
    input.setAttribute('name', p);
    input.setAttribute('value', params[p]);
    form.appendChild(input);
  }

  // Add form to page and submit it to open the OAuth 2.0 endpoint.
  document.body.appendChild(form);
  form.submit();
}

הדרך החדשה

חוויית משתמש בחלון קופץ של GIS

בדוגמה הזו מוצגת רק ספריית JavaScript של Google Identity Service שמשתמשת במודל קוד ההרשאה, תיבת דו-שיח קופצת לקבלת הסכמה מהמשתמש ומטפל בקריאה חוזרת לקבלת קוד ההרשאה מ-Google. הוא נועד להמחיש את מספר השלבים המינימלי שנדרשים כדי להגדיר לקוח, לקבל הסכמה ולשלוח קוד הרשאה לפלטפורמת ה-Backend.

<!DOCTYPE html>
<html>
  <head>
    <script src="https://accounts.google.com/gsi/client" onload="initClient()" async defer></script>
  </head>
  <body>
    <script>
      var client;
      function initClient() {
        client = google.accounts.oauth2.initCodeClient({
          client_id: 'YOUR_CLIENT_ID',
          scope: 'https://www.googleapis.com/auth/calendar.readonly',
          ux_mode: 'popup',
          callback: (response) => {
            var code_receiver_uri = 'YOUR_AUTHORIZATION_CODE_ENDPOINT_URI',
            // Send auth code to your backend platform
            const xhr = new XMLHttpRequest();
            xhr.open('POST', code_receiver_uri, true);
            xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
            xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
            xhr.onload = function() {
              console.log('Signed in as: ' + xhr.responseText);
            };
            xhr.send('code=' + response.code);
            // After receipt, the code is exchanged for an access token and
            // refresh token, and the platform then updates this web app
            // running in user's browser with the requested calendar info.
          },
        });
      }
      function getAuthCode() {
        // Request authorization code and obtain user consent
        client.requestCode();
      }
    </script>
    <button onclick="getAuthCode();">Load Your Calendar</button>
  </body>
</html>

חוויית משתמש בהפניה אוטומטית ב-GIS

מודל קוד ההרשאה תומך במצבי חוויית המשתמש של חלון קופץ והפניה אוטומטית כדי לשלוח קוד הרשאה לכל משתמש לנקודת הקצה שמתארחת בפלטפורמה שלכם. כאן מוצג מצב חוויית המשתמש של ההפניה האוטומטית:

<!DOCTYPE html>
<html>
  <head>
    <script src="https://accounts.google.com/gsi/client" onload="initClient()" async defer></script>
  </head>
  <body>
    <script>
      var client;
      function initClient() {
        client = google.accounts.oauth2.initCodeClient({
          client_id: 'YOUR_CLIENT_ID',
          scope: 'https://www.googleapis.com/auth/calendar.readonly \
                  https://www.googleapis.com/auth/photoslibrary.readonly',
          ux_mode: 'redirect',
          redirect_uri: 'YOUR_AUTHORIZATION_CODE_ENDPOINT_URI'
        });
      }
      // Request an access token
      function getAuthCode() {
        // Request authorization code and obtain user consent
        client.requestCode();
      }
    </script>
    <button onclick="getAuthCode();">Load Your Calendar</button>
  </body>
</html>

ספריות JavaScript

Google Identity Services היא ספריית JavaScript יחידה שמשמשת לאימות משתמשים ולהרשאת גישה. היא מאגדת ומחליפה תכונות ופונקציות שנמצאות בספריות ובמודולים שונים:

פעולות שצריך לבצע כשעוברים אל שירותי הזהויות:

ספריית JS קיימת ספריית JS חדשה הערות
apis.google.com/js/api.js accounts.google.com/gsi/client מוסיפים ספרייה חדשה ופועלים לפי התהליך המרומז.
apis.google.com/js/client.js accounts.google.com/gsi/client הוספת ספרייה חדשה ותהליך הרשאת הגישה.

הסבר מהיר על ספרייה

השוואה בין אובייקטים ושיטות בספרייה של הלקוח הישן Google Sign-In JavaScript לבין הספרייה של הלקוח החדש Google Identity Services, והערות עם מידע נוסף ופעולות שצריך לבצע במהלך ההעברה.

ישן חדש הערות
אובייקט GoogleAuth ושיטות שמשויכות אליו:
GoogleAuth.attachClickHandler() הסרה
GoogleAuth.currentUser.get() הסרה
GoogleAuth.currentUser.listen() הסרה
GoogleAuth.disconnect() google.accounts.oauth2.revoke מחליפים את הישן בחדש. אפשר גם לבטל את הגישה בכתובת https://myaccount.google.com/permissions
GoogleAuth.grantOfflineAccess() כדי להסיר, פועלים לפי השלבים של הרשאה באמצעות קוד.
GoogleAuth.isSignedIn.get() הסרה
GoogleAuth.isSignedIn.listen() הסרה
GoogleAuth.signIn() הסרה
GoogleAuth.signOut() הסרה
GoogleAuth.then() הסרה
אובייקט GoogleUser ושיטות שמשויכות אליו:
GoogleUser.disconnect() google.accounts.id.revoke מחליפים את הישן בחדש. אפשר גם לבטל את הגישה בכתובת https://myaccount.google.com/permissions
GoogleUser.getAuthResponse() requestCode() or requestAccessToken() החלפת הישן בחדש
GoogleUser.getBasicProfile() הסרה. במקום זאת, צריך להשתמש באסימון מזהה. אפשר לעיין במאמר בנושא מעבר מ'כניסה באמצעות חשבון Google'.
GoogleUser.getGrantedScopes() hasGrantedAnyScope() החלפת הישן בחדש
GoogleUser.getHostedDomain() הסרה
GoogleUser.getId() הסרה
GoogleUser.grantOfflineAccess() כדי להסיר, פועלים לפי השלבים של הרשאה באמצעות קוד.
GoogleUser.grant() הסרה
GoogleUser.hasGrantedScopes() hasGrantedAnyScope() החלפת הישן בחדש
GoogleUser.isSignedIn() הסרה
GoogleUser.reloadAuthResponse() requestAccessToken() מסירים את אסימון הגישה הישן, מתקשרים לאסימון חדש כדי להחליף אסימון גישה שפג תוקפו או שבוטל.
אובייקט gapi.auth2 ושיטות שמשויכות אליו:
אובייקט gapi.auth2.AuthorizeConfig TokenClientConfig או CodeClientConfig החלפת הישן בחדש
אובייקט gapi.auth2.AuthorizeResponse הסרה
אובייקט gapi.auth2.AuthResponse הסרה
gapi.auth2.authorize() requestCode() or requestAccessToken() החלפת הישן בחדש
gapi.auth2.ClientConfig() TokenClientConfig או CodeClientConfig החלפת הישן בחדש
gapi.auth2.getAuthInstance() הסרה
gapi.auth2.init() initTokenClient() or initCodeClient() החלפת הישן בחדש
אובייקט gapi.auth2.OfflineAccessOptions הסרה
אובייקט gapi.auth2.SignInOptions הסרה
אובייקט gapi.signin2 והשיטות שמשויכות אליו:
gapi.signin2.render() הסרה. טעינת HTML DOM של הרכיב g_id_signin או קריאת JS ל-google.accounts.id.renderButton מפעילה את הכניסה של המשתמש לחשבון Google.

פרטי כניסה לדוגמה

פרטי כניסה קיימים

Google Sign-In platform library,‏ Google API Client Library for JavaScript או קריאות ישירות לנקודות הקצה של Google OAuth 2.0 מחזירות גם אסימון גישה מסוג OAuth 2.0 וגם אסימון מזהה של OpenID Connect בתגובה אחת.

דוגמה לתגובה שמכילה גם את access_token וגם את id_token:

  {
    "token_type": "Bearer",
    "access_token": "ya29.A0ARrdaM-SmArZaCIh68qXsZSzyeU-8mxhQERHrP2EXtxpUuZ-3oW8IW7a6D2J6lRnZrRj8S6-ZcIl5XVEqnqxq5fuMeDDH_6MZgQ5dgP7moY-yTiKR5kdPm-LkuPM-mOtUsylWPd1wpRmvw_AGOZ1UUCa6UD5Hg",
    "scope": "https://www.googleapis.com/auth/calendar.readonly",
    "login_hint": "AJDLj6I2d1RH77cgpe__DdEree1zxHjZJr4Q7yOisoumTZUmo5W2ZmVFHyAomUYzLkrluG-hqt4RnNxrPhArd5y6p8kzO0t8xIfMAe6yhztt6v2E-_Bb4Ec3GLFKikHSXNh5bI-gPrsI",
    "expires_in": 3599,
    "id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjkzNDFhYmM0MDkyYjZmYzAzOGU0MDNjOTEwMjJkZDNlNDQ1MzliNTYiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJhY2NvdW50cy5nb29nbGUuY29tIiwiYXpwIjoiNTM4MzQ0NjUzMjU1LTc1OGM1aDVpc2M0NXZnazI3ZDhoOGRlYWJvdnBnNnRvLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwiYXVkIjoiNTM4MzQ0NjUzMjU1LTc1OGM1aDVpc2M0NXZnazI3ZDhoOGRlYWJvdnBnNnRvLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwic3ViIjoiMTE3NzI2NDMxNjUxOTQzNjk4NjAwIiwiaGQiOiJnb29nbGUuY29tIiwiZW1haWwiOiJkYWJyaWFuQGdvb2dsZS5jb20iLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiYXRfaGFzaCI6IkJBSW55TjN2MS1ZejNLQnJUMVo0ckEiLCJuYW1lIjoiQnJpYW4gRGF1Z2hlcnR5IiwicGljdHVyZSI6Imh0dHBzOi8vbGgzLmdvb2dsZXVzZXJjb250ZW50LmNvbS9hLS9BT2gxNEdnenAyTXNGRGZvbVdMX3VDemRYUWNzeVM3ZGtxTE5ybk90S0QzVXNRPXM5Ni1jIiwiZ2l2ZW5fbmFtZSI6IkJyaWFuIiwiZmFtaWx5X25hbWUiOiJEYXVnaGVydHkiLCJsb2NhbGUiOiJlbiIsImlhdCI6MTYzODk5MTYzOCwiZXhwIjoxNjM4OTk1MjM4LCJqdGkiOiI5YmRkZjE1YWFiNzE2ZDhjYmJmNDYwMmM1YWM3YzViN2VhMDQ5OTA5In0.K3EA-3Adw5HA7O8nJVCsX1HmGWxWzYk3P7ViVBb4H4BoT2-HIgxKlx1mi6jSxIUJGEekjw9MC-nL1B9Asgv1vXTMgoGaNna0UoEHYitySI23E5jaMkExkTSLtxI-ih2tJrA2ggfA9Ekj-JFiMc6MuJnwcfBTlsYWRcZOYVw3QpdTZ_VYfhUu-yERAElZCjaAyEXLtVQegRe-ymScra3r9S92TA33ylMb3WDTlfmDpWL0CDdDzby2asXYpl6GQ7SdSj64s49Yw6mdGELZn5WoJqG7Zr2KwIGXJuSxEo-wGbzxNK-mKAiABcFpYP4KHPEUgYyz3n9Vqn2Tfrgp-g65BQ",
    "session_state": {
      "extraQueryParams": {
        "authuser": "0"
      }
    },
    "first_issued_at": 1638991637982,
    "expires_at": 1638995236982,
    "idpId": "google"
  }

Google Identity Services credential

הספרייה של Google Identity Services מחזירה:

  • או טוקן גישה כשמשתמשים בו לאימות:

    {
      "access_token": "ya29.A0ARrdaM_LWSO-uckLj7IJVNSfnUityT0Xj-UCCrGxFQdxmLiWuAosnAKMVQ2Z0LLqeZdeJii3TgULp6hR_PJxnInBOl8UoUwWoqsrGQ7-swxgy97E8_hnzfhrOWyQBmH6zs0_sUCzwzhEr_FAVqf92sZZHphr0g",
      "token_type": "Bearer",
      "expires_in": 3599,
      "scope": "https://www.googleapis.com/auth/calendar.readonly"
    }
    
  • או אסימון מזהה כשמשתמשים בו לאימות:

    {
      "clientId": "538344653255-758c5h5isc45vgk27d8h8deabovpg6to.apps.googleusercontent.com",
      "credential": "eyJhbGciOiJSUzI1NiIsImtpZCI6ImMxODkyZWI0OWQ3ZWY5YWRmOGIyZTE0YzA1Y2EwZDAzMjcxNGEyMzciLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJuYmYiOjE2MzkxNTcyNjQsImF1ZCI6IjUzODM0NDY1MzI1NS03NThjNWg1aXNjNDV2Z2syN2Q4aDhkZWFib3ZwZzZ0by5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbSIsInN1YiI6IjExNzcyNjQzMTY1MTk0MzY5ODYwMCIsIm5vbmNlIjoiZm9vYmFyIiwiaGQiOiJnb29nbGUuY29tIiwiZW1haWwiOiJkYWJyaWFuQGdvb2dsZS5jb20iLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiYXpwIjoiNTM4MzQ0NjUzMjU1LTc1OGM1aDVpc2M0NXZnazI3ZDhoOGRlYWJvdnBnNnRvLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwibmFtZSI6IkJyaWFuIERhdWdoZXJ0eSIsInBpY3R1cmUiOiJodHRwczovL2xoMy5nb29nbGV1c2VyY29udGVudC5jb20vYS0vQU9oMTRHZ3pwMk1zRkRmb21XTF91Q3pkWFFjc3lTN2RrcUxOcm5PdEtEM1VzUT1zOTYtYyIsImdpdmVuX25hbWUiOiJCcmlhbiIsImZhbWlseV9uYW1lIjoiRGF1Z2hlcnR5IiwiaWF0IjoxNjM5MTU3NTY0LCJleHAiOjE2MzkxNjExNjQsImp0aSI6IjRiOTVkYjAyZjU4NDczMmUxZGJkOTY2NWJiMWYzY2VhYzgyMmI0NjUifQ.Cr-AgMsLFeLurnqyGpw0hSomjOCU4S3cU669Hyi4VsbqnAV11zc_z73o6ahe9Nqc26kPVCNRGSqYrDZPfRyTnV6g1PIgc4Zvl-JBuy6O9HhClAK1HhMwh1FpgeYwXqrng1tifmuotuLQnZAiQJM73Gl-J_6s86Buo_1AIx5YAKCucYDUYYdXBIHLxrbALsA5W6pZCqqkMbqpTWteix-G5Q5T8LNsfqIu_uMBUGceqZWFJALhS9ieaDqoxhIqpx_89QAr1YlGu_UO6R6FYl0wDT-nzjyeF5tonSs3FHN0iNIiR3AMOHZu7KUwZaUdHg4eYkU-sQ01QNY_11keHROCRQ",
      "select_by": "user"
    }
    

תגובה לא תקינה של טוקן

דוגמה לתשובה מ-Google כשמנסים לשלוח בקשת API באמצעות אסימון גישה שפג תוקפו, שבוטל או שלא תקין:

כותרות תגובה של HTTP

  www-authenticate: Bearer realm="https://accounts.google.com/", error="invalid_token"

גוף התשובה

  {
    "error": {
      "code": 401,
      "message": "Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.",
      "errors": [
        {
          "message": "Invalid Credentials",
          "domain": "global",
          "reason": "authError",
          "location": "Authorization",
          "locationType": "header"
        }
      ],
      "status": "UNAUTHENTICATED"
    }
  }