מעבר אל Google Identity Services

סקירה כללית

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

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

במדריך הזה נסביר:

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

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

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

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

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

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

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

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

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

  • ההטמעה שלכם מבוססת על:

  • האפליקציה פועלת גם בדפדפן של המשתמש וגם בפלטפורמת הקצה העורפי.

  • פלטפורמת הקצה העורפי שלכם מארחת נקודת קצה (endpoint) של קוד הרשאה.

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

  • טוקני הרענון מנוהלים ונשמרים בפלטפורמת הקצה העורפי שלכם.

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

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

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

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

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

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

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

לקבל אסימון גישה לשימוש בדפדפן כשהמשתמש נוכח.

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

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

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

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

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

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

בקטע הזה נסקור את השינויים שתבצעו באפליקציית האינטרנט בדפדפן כשתעברו לספריית 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 רישום השימוש בפונקציונליות שהוצאה משימוש במסוף JS. כדאי גם לתעד באחסון הסשן כשמוגדר שם מפתח אופציונלי: informational:key-name.

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

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

המודול gapi.auth2 מנהל את אימות המשתמשים לצורך כניסה ואת זרם הענקת הגישה המשתמע לצורך הרשאה. צריך להחליף את המודול הזה, שהוצא משימוש, ואת האובייקטים והשיטות שלו בספרייה של Google 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 שניתנות לקריאה ממסמך Discovery, מהאפשרות לשלוח כמה קריאות ל-API באצווה ומהפונקציונליות של ניהול CORS.

קובצי Cookie

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

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

פרטי כניסה

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

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

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

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

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

Methods

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

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

שירותי הזהויות מפרידים את פרטי הכניסה בדפדפן לטוקן של מזהה ולטוקן גישה. השינוי הזה לא חל על פרטי כניסה שהתקבלו באמצעות קריאות ישירות לנקודות קצה של Google OAuth 2.0 מפלטפורמת הקצה העורפי, או באמצעות ספריות שפועלות בשרת מאובטח בפלטפורמה, כמו 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() כדי להגדיר את אפליקציית האינטרנט, לפי הדוגמה שמפורטת בקטע אתחול של Code Client.

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

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

אובייקטים:

  • gapi.auth2.AuthorizeConfig

שיטות:

  • gapi.auth2.init()

פרמטרים:

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

בקשה לטוקן

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

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

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

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

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

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

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

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

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

טוקנים שפג תוקפם

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

ביטול טוקן

בעלי חשבון 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 אם עדיין אין סשן פעיל.
  • שימוש ישיר בשדה פרטי הכניסה 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() לפי הדוגמה הזו של הרשאות פרטניות.

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

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

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

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

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

הדרך הישנה

ספריית הלקוח של 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>

נקודות קצה (endpoints) של 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 the Google authorization 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 the Google authorization 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 ל-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 ל-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 Service, אפשר להשתמש בהפניה לכתובת URL כדי להחזיר קוד הרשאה ישירות לנקודת הקצה של האסימון בקצה העורפי, או בגורם מטפל בקריאה חוזרת של JavaScript שפועל בדפדפן של המשתמש ומעביר את התגובה לפלטפורמה שלכם. בכל מקרה, פלטפורמת הקצה העורפי תשלים את תהליך ההרשאה באמצעות 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 the Google authorization 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 Services שמשתמשת במודל של קוד ההרשאה, תיבת דו-שיח קופצת להסכמת המשתמש וגורם מטפל בקריאה חוזרת כדי לקבל את קוד ההרשאה מ-Google. הוא נועד להמחיש את מספר השלבים המינימלי שנדרש כדי להגדיר לקוח, לקבל הסכמה ולשלוח קוד הרשאה לפלטפורמת הקצה העורפי.

<!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

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

<!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 אחת שמשמשת לאימות ולהרשאה של משתמשים. היא מאחדת ומחליפה תכונות ופונקציונליות שנמצאות בכמה ספריות ומודולים שונים:

פעולות שצריך לבצע כשעוברים ל-Identity Services:

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

מדריך מהיר לספרייה

השוואה בין האובייקטים והשיטות של ספריית הלקוח JavaScript לכניסה באמצעות חשבון Google הישנה לבין הספרייה 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() או 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() או requestAccessToken() החלפת הישן בחדש
gapi.auth2.ClientConfig() TokenClientConfig או CodeClientConfig החלפת הישן בחדש
gapi.auth2.getAuthInstance() הסרה
gapi.auth2.init() initTokenClient() או initCodeClient() החלפת הישן בחדש
אובייקט gapi.auth2.OfflineAccessOptions הסרה
אובייקט gapi.auth2.SignInOptions הסרה
האובייקט gapi.signin2 והשיטות שמשויכות אליו:
gapi.signin2.render() הסרה. טעינת HTML DOM של הרכיב g_id_signin או קריאת JS אל google.accounts.id.renderButton מפעילה כניסת משתמש לחשבון Google.

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

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

ספריית הפלטפורמה של כניסה באמצעות חשבון Google, ספריית הלקוח של Google API ל-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

ספריית 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"
    }
  }