OAuth 2.0 לאפליקציות אינטרנט בצד הלקוח

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

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

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

ספריית הלקוח של Google APIs ושירותי Google Identity

אם אתם משתמשים בספריית הלקוח של Google APIs ל-JavaScript כדי לבצע קריאות מורשות ל-Google, עליך להשתמש ב- ספריית ה-JavaScript של Google Identity Services לטיפול בתהליך OAuth 2.0. צריך לעיין ב-Google שירותי זהות את מודל האסימון, שמבוסס על תהליך ההרשאה המשתמעת של OAuth 2.0.

דרישות מוקדמות

הפעלת ממשקי API לפרויקט

כל אפליקציה שקוראת ל-Google APIs צריכה להפעיל את ממשקי ה-API האלה API Console

כדי להפעיל API לפרויקט:

  1. Open the API Library ב- Google API Console.
  2. If prompted, select a project, or create a new one.
  3. API Library מציגים את כל ממשקי ה-API הזמינים, מקובצים לפי מוצר המשפחה והפופולריות. אם ממשק ה-API שאתם רוצים להפעיל לא מופיע ברשימה, צריך להשתמש בחיפוש כדי למצוא אותו, או ללחוץ על הצגת הכול במשפחת המוצרים שאליה הוא שייך.
  4. בוחרים את ה-API שרוצים להפעיל ולוחצים על הלחצן הפעלה.
  5. If prompted, enable billing.
  6. If prompted, read and accept the API's Terms of Service.

יצירת פרטי כניסה להרשאה

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

  1. Go to the Credentials page.
  2. לוחצים על Create credentials > מזהה הלקוח ב-OAuth.
  3. בוחרים בסוג האפליקציה Web application.
  4. ממלאים את הטופס. אפליקציות המשתמשות ב-JavaScript כדי לבצע בקשות מורשות של Google API חייבים לציין מקורות JavaScript מורשים. המקורות מזהים את הדומיינים שהאפליקציה שלך יכולה לשלוח בקשות לשרת OAuth 2.0. המקורות האלה חייבים לעמוד בדרישות לכללי האימות של Google.

זיהוי של היקפי גישה

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

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

המסמך היקפי API של OAuth 2.0 מכיל רשימת היקפים שבהם תוכלו להשתמש כדי לגשת ל-Google APIs.

קבלת אסימוני גישה מסוג OAuth 2.0

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

שלב 1: הפניה אוטומטית לשרת OAuth 2.0 של Google

כדי לבקש הרשאת גישה לנתונים של משתמש, צריך להפנות את המשתמש ל-OAuth 2.0 של Google השרת.

נקודות קצה ב-OAuth 2.0

יצירת כתובת URL כדי לבקש גישה מנקודת הקצה מסוג OAuth 2.0 של Google ב- https://accounts.google.com/o/oauth2/v2/auth ניתן לגשת לנקודת הקצה הזו באמצעות HTTPS. חיבורי HTTP רגילים נדחים.

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

פרמטרים
client_id חובה

מזהה הלקוח של האפליקציה. אפשר למצוא את הערך הזה API Console Credentials page.

redirect_uri חובה

קובע להיכן שרת ה-API מפנה את המשתמש מחדש אחרי שהמשתמש משלים את תהליך ההרשאה. הערך חייב להתאים בדיוק לאחד ממזהי ה-URI המורשים להפניה מחדש עבור לקוח OAuth 2.0, שאותו הגדרת באפליקציית הלקוח API Console Credentials page. אם הערך הזה לא תואם ה-URI הייעודי להפניה אוטומטית ב-client_id שיסופק, תקבלו שגיאה אחת (redirect_uri_mismatch).

חשוב לשים לב לסכימה http או https, לאותיות רישיות ולקו נטוי בסוף ('/') חייבת להיות התאמה.

response_type חובה

אפליקציות JavaScript צריכות להגדיר את ערך הפרמטר ל-token. הזה מורה לשרת ההרשאות של Google להחזיר את אסימון הגישה name=value צמד במזהה הקטע של ה-URI (#) שאליו המשתמש מופנה לכתובת אחרת אחרי השלמת תהליך ההרשאה.

scope חובה

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

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

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

state המלצות

מציינת כל ערך מחרוזת שהאפליקציה שלכם משתמשת בו כדי לשמור על מצב בין בקשת ההרשאה והתגובה של שרת ההרשאות. השרת מחזיר את הערך המדויק שאתם שולחים בתור צמד name=value מזהה קטע של כתובת URL (#) של redirect_uri אחרי שהמשתמש הביע הסכמה או ידחה את בקשת הבקשה בקשת גישה.

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

include_granted_scopes אופציונלי

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

login_hint אופציונלי

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

מגדירים את ערך הפרמטר לכתובת אימייל או למזהה sub, מקביל למזהה Google של המשתמש.

prompt אופציונלי

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

הערכים האפשריים הם:

none אין להציג מסכים של אימות או הסכמה. אין לציין באמצעות ערכים אחרים.
consent מבקשים מהמשתמשים להביע הסכמה.
select_account לבקש מהמשתמש לבחור חשבון.

דוגמה להפניה מחדש לשרת ההרשאות של Google

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

https://accounts.google.com/o/oauth2/v2/auth?
 scope=https%3A//www.googleapis.com/auth/drive.metadata.readonly&
 include_granted_scopes=true&
 response_type=token&
 state=state_parameter_passthrough_value&
 redirect_uri=https%3A//oauth2.example.com/code&
 client_id=client_id

לאחר יצירת כתובת ה-URL של הבקשה, הפנה את המשתמש אליה.

קוד לדוגמה של JavaScript

קטע הקוד הבא של JavaScript מראה איך להתחיל את תהליך ההרשאה ב- JavaScript בלי להשתמש בספריית הלקוח של Google APIs ל-JavaScript. מאז ה-OAuth הזה נקודת קצה 2.0 לא תומכת בשיתוף משאבים בין מקורות (CORS), קטע הקוד יוצר שפותח את הבקשה לנקודת הקצה הזו.

/*
 * 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 <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_REDIRECT_URI',
                '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();
}

שלב 2: Google מבקשת הסכמה מהמשתמש

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

הבקשה שלך לא צריכה לעשות דבר בשלב הזה כי היא ממתינה לתשובה מאת שרת OAuth 2.0 של Google שמציין אם ניתנה גישה. התשובה הזו מוסברת בשלב הבא.

שגיאות

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

admin_policy_enforced

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

disallowed_useragent

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

Android

מפתחי Android עשויים להיתקל בהודעת השגיאה הזו כשהם פותחים בקשות הרשאה ב android.webkit.WebView מפתחים צריכים להשתמש במקום זאת בספריות Android כמו כניסה באמצעות חשבון Google ל-Android או OpenID Foundation AppAuth ל-Android.

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

iOS

מפתחי iOS ו-macOS עשויים להיתקל בשגיאה הזו כשהם יפתחו בקשות הרשאה WKWebView מפתחים צריכים במקום זאת להשתמש בספריות iOS כמו כניסה באמצעות חשבון Google ל-iOS או OpenID Foundation AppAuth ל-iOS.

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

org_internal

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

invalid_client

המקור שממנו נשלחה הבקשה לא מורשה עבור הלקוח הזה. צפייה origin_mismatch

invalid_grant

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

origin_mismatch

הסכימה, הדומיין ו/או היציאה של ה-JavaScript שממנו הגיעה בקשת ההרשאה אינם רשאים תואם ל-URI מורשה של מקור JavaScript שרשום עבור מזהה הלקוח ב-OAuth. הבדיקה אושרה מקורות JavaScript ב- Google API Console Credentials page.

redirect_uri_mismatch

הredirect_uri שהועבר בבקשת ההרשאה לא תואם לחשבון מורשה ה-URI להפניה אוטומטית במזהה הלקוח ב-OAuth. לבדוק את מזהי ה-URI המורשים להפניה אוטומטית Google API Console Credentials page

הסכימה, הדומיין ו/או היציאה של ה-JavaScript שממנו הגיעה בקשת ההרשאה אינם רשאים תואם ל-URI מורשה של מקור JavaScript שרשום עבור מזהה הלקוח ב-OAuth. צפייה מקורות JavaScript מורשים Google API Console Credentials page

הפרמטר redirect_uri עשוי להתייחס לתהליך של OAuth מחוץ למסגרת (OOB) שכולל הוצא משימוש ולא נתמך יותר. עיינו ב מדריך ההעברה כדי לעדכן את של Google Analytics.

invalid_request

יש בעיה בבקשה ששלחת. יכולות להיות לכך כמה סיבות:

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

שלב 3: טיפול בתגובה לשרת OAuth 2.0

נקודות קצה ב-OAuth 2.0

שרת OAuth 2.0 שולח תגובה ל-redirect_uri שצוין בקשה לאסימון גישה.

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

  • תגובה של אסימון גישה:

    https://oauth2.example.com/callback#access_token=4/P7q7W91&token_type=Bearer&expires_in=3600

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

  • תגובת שגיאה:
    https://oauth2.example.com/callback#error=access_denied

דוגמה של תגובת שרת OAuth 2.0

כדי לבדוק את התהליך הזה, לוחצים על כתובת ה-URL לדוגמה הבאה, הרשאת קריאה בלבד להצגת מטא-נתונים של קבצים ב-Google Drive:

https://accounts.google.com/o/oauth2/v2/auth?
 scope=https%3A//www.googleapis.com/auth/drive.metadata.readonly&
 include_granted_scopes=true&
 response_type=token&
 state=state_parameter_passthrough_value&
 redirect_uri=https%3A//oauth2.example.com/code&
 client_id=client_id

בסיום התהליך של OAuth 2.0, תופנו אל http://localhost/oauth2callback כתובת האתר הזו תניב שגיאה אחת (404 NOT FOUND), אלא אם המכונה המקומית מציגה קובץ בכתובת הכתובת הזאת. בשלב הבא מוצג פרטים נוספים על המידע שהוחזר URI כשהמשתמש מופנה בחזרה לאפליקציה.

קריאה ל-Google APIs

נקודות קצה ב-OAuth 2.0

לאחר שהאפליקציה שלך מקבלת אסימון גישה, אפשר להשתמש באסימון כדי לבצע קריאות API בשם נתון חשבון משתמש, אם היקפי הגישה הנדרשים על ידי ה-API הוענקו. כדי לעשות את זה, צריך לכלול אסימון הגישה בבקשה ל-API על ידי הכללת שאילתת access_token או ערך Bearer של כותרת HTTP בAuthorization. כשהדבר אפשרי, עדיף להשתמש בכותרת HTTP, כי מחרוזות השאילתה בדרך כלל גלויות ביומני השרת. במרבית במקרים מסוימים תוכלו להשתמש בספריית לקוח כדי להגדיר את הקריאות ל-Google APIs (לדוגמה, שליחת קריאה ל-Drive Files API).

אפשר לנסות את כל ממשקי ה-API של Google ולצפות בהיקף שלהם בקישור OAuth 2.0 Playground

דוגמאות ל-HTTP GET

קריאה ל drive.files נקודת הקצה (Drive Files API) באמצעות Authorization: Bearer HTTP עשויה להיראות כך. שימו לב שתצטרכו לציין אסימון גישה משלכם:

GET /drive/v2/files HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer access_token

זוהי קריאה לאותו API בשביל המשתמש המאומת באמצעות access_token פרמטר של מחרוזת שאילתה:

GET https://www.googleapis.com/drive/v2/files?access_token=access_token

curl דוגמאות

אפשר לבדוק את הפקודות האלה באמצעות אפליקציית שורת הפקודה curl. הנה דוגמה שמשתמשת באפשרות של כותרת HTTP (מועדף):

curl -H "Authorization: Bearer access_token" https://www.googleapis.com/drive/v2/files

לחלופין, אפשרות הפרמטר של מחרוזת השאילתה:

curl https://www.googleapis.com/drive/v2/files?access_token=access_token

קוד לדוגמה של JavaScript

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

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

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) {
  console.log(xhr.response);
};
xhr.send(null);

דוגמה מלאה

נקודות קצה ב-OAuth 2.0

דוגמת הקוד הזו מדגימה איך להשלים את תהליך OAuth 2.0 ב-JavaScript, בלי להשתמש ספריית הלקוח של Google APIs ל-JavaScript. הקוד מיועד לדף HTML שמוצג בו לחצן לנסות לשלוח בקשת API. אם תלחצו על הלחצן, הקוד בודק אם הדף שמר אסימון הגישה ל-API באחסון המקומי של הדפדפן. אם כן, היא תריץ את בקשת ה-API. אחרת, מתחיל זרימת OAuth 2.0.

לתהליך OAuth 2.0, הדף מבצע את השלבים הבאים:

  1. הוא מפנה את המשתמש לשרת OAuth 2.0 של Google, שמבקש גישה היקף הרשאות אחד (https://www.googleapis.com/auth/drive.metadata.readonly).
  2. אחרי הענקת (או דחייה) של הרשאת גישה להיקף בקשה אחד או יותר, המשתמש מופנה אל הדף המקורי, שמנתח את אסימון הגישה מהמחרוזת של מזהה המקטע.
  3. הדף משתמש באסימון הגישה כדי לבצע את בקשת ה-API לדוגמה.

    בקשת ה-API מפעילה את ה-method about.get של Drive API לאחזור מידע על חשבון Google Drive של המשתמש המורשה.

  4. אם הבקשה מבוצעת בהצלחה, תגובת ה-API תתועד בניפוי הבאגים של הדפדפן במסוף.

אפשר לבטל את הגישה לאפליקציה דרך הדף הרשאות של חשבון Google. האפליקציה תופיע כהדגמה של OAuth 2.0 ל-Google API Docs.

כדי להריץ את הקוד הזה באופן מקומי, צריך להגדיר ערכים עבור YOUR_CLIENT_ID YOUR_REDIRECT_URI משתנים שתואמים פרטי כניסה להרשאה. המשתנה YOUR_REDIRECT_URI צריך להיות מוגדר לאותה כתובת אתר שבה הדף מוצג. הערך צריך להתאים בדיוק לאחד מהערכים מזהי ה-URI המורשים להפניה אוטומטית עבור לקוח OAuth 2.0, שאותם הגדרת API Console Credentials pageאם המיקום הערך הזה לא תואם ל-URI מורשה, תקבלו redirect_uri_mismatch שגיאה. לפרויקט שלכם צריך גם להיות הפעלת ה-API המתאים לבקשה הזו.

<html><head></head><body>
<script>
  var YOUR_CLIENT_ID = 'REPLACE_THIS_VALUE';
  var YOUR_REDIRECT_URI = 'REPLACE_THIS_VALUE';

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

      trySampleRequest();
    } else {
      console.log('State mismatch. Possible CSRF attack');
    }
  }

  // Function to generate a random state value
  function generateCryptoRandomState() {
    const randomValues = new Uint32Array(2);
    window.crypto.getRandomValues(randomValues);

    // Encode as UTF-8
    const utf8Encoder = new TextEncoder();
    const utf8Array = utf8Encoder.encode(
      String.fromCharCode.apply(null, randomValues)
    );

    // Base64 encode the UTF-8 data
    return btoa(String.fromCharCode.apply(null, utf8Array))
      .replace(/\+/g, '-')
      .replace(/\//g, '_')
      .replace(/=+$/, '');
  }

  // 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() {
    // create random state value and store in local storage
    var state = generateCryptoRandomState();
    localStorage.setItem('state', state);

    // 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': state,
                  '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>

כללי אימות של מקור JavaScript

Google מחילה את כללי האימות הבאים על מקורות JavaScript כדי לעזור מפתחים לשמור על אבטחת האפליקציות שלהם. המקורות של JavaScript חייבים לפעול בהתאם לכללים האלה. בRFC 3986 סעיף 3 מופיע של דומיין, מארח וסכימה, שמוזכרת בהמשך.

כללי אימות
סכמה

מקורות JavaScript חייבים להשתמש בסכמת HTTPS, ולא ב-HTTP פשוט. מזהי URI של מארחים מקומיים (כולל מזהי URI של כתובות IP של Localhost) פטורים מהכלל הזה.

מארח

מארחים לא יכולים להיות כתובות IP גולמיות. כתובות IP של מארח מקומי פטורות מהכלל הזה.

דומיין
  • מארח דומיינים ברמה העליונה (דומיינים ברמה עליונה) חייבות להשתייך לרשימת הסיומות הציבוריות.
  • הדומיינים של המארח לא יכולים להיות “googleusercontent.com”.
  • מקורות JavaScript לא יכולים להכיל דומיינים של מקצרי כתובות URL (למשל, goo.gl) אלא אם הדומיין הוא בבעלות האפליקציה.
  • פרטי משתמשים

    מקורות JavaScript לא יכולים להכיל את רכיב המשנה userinfo.

    נתיב

    מקורות JavaScript לא יכולים להכיל את רכיב הנתיב.

    שאילתה

    מקורות JavaScript לא יכולים להכיל את רכיב השאילתה.

    מקטע

    מקורות של JavaScript לא יכולים להכיל את רכיב המקטע.

    דמויות מקורות JavaScript לא יכולים לכלול תווים מסוימים, כולל:
    • תווים כלליים לחיפוש ('*')
    • תווי ASCII שאינם ניתנים להדפסה
    • קידודים באחוזים לא חוקיים (כל אחוז קידוד שלא תואם לקידוד כתובות URL סימן אחוז ואחריו שתי ספרות הקסדצימליות
    • תווי NULL מקודדים, לדוגמה, %00, %C0%80)

    הרשאה מצטברת

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

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

    במקרה כזה, בזמן הכניסה האפליקציה עשויה לבקש את openid וגם profile היקפי הרשאות לביצוע כניסה בסיסית, ומאוחר יותר יבקשו את היקף הרשאות אחד (https://www.googleapis.com/auth/drive.file) בזמן הבקשה הראשונה לשמירה של מיקס.

    הכללים הבאים חלים על אסימון גישה שמתקבל מהרשאה מצטברת:

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

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

    נקודות קצה ב-OAuth 2.0

    כדי להוסיף היקפים לאסימון גישה קיים, צריך לכלול את include_granted_scopes בבקשה לשרת OAuth 2.0 של Google.

    קטע הקוד הבא מדגים איך לעשות את זה. קטע הקוד מניח שאחסנתם היקפי ההרשאות שעבורם אסימון הגישה בתוקף באחסון המקומי של הדפדפן. (ה הקוד הדוגמה המלאה מאחסן רשימת היקפים של אסימון הגישה חוקי על ידי הגדרת המאפיין oauth2-test-params.scope בקובץ המקומי של הדפדפן storage.)

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

    var SCOPE = 'https://www.googleapis.com/auth/drive.metadata.readonly';
    var params = JSON.parse(localStorage.getItem('oauth2-test-params'));
    
    var current_scope_granted = false;
    if (params.hasOwnProperty('scope')) {
      var scopes = params['scope'].split(' ');
      for (var s = 0; s < scopes.length; s++) {
        if (SCOPE == scopes[s]) {
          current_scope_granted = true;
        }
      }
    }
    
    if (!current_scope_granted) {
      oauth2SignIn(); // This function is defined elsewhere in this document.
    } else {
      // Since you already have access, you can proceed with the API request.
    }

    ביטול אסימון

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

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

    נקודות קצה ב-OAuth 2.0

    כדי לבטל אסימון באופן פרוגרמטי, האפליקציה שולחת בקשה ל- https://oauth2.googleapis.com/revoke והוא כולל את האסימון כפרמטר:

    curl -d -X -POST --header "Content-type:application/x-www-form-urlencoded" \
            https://oauth2.googleapis.com/revoke?token={token}

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

    אם הביטול בוצע בהצלחה, קוד סטטוס ה-HTTP של התשובה 200 במקרים של שגיאות, מוחזר קוד מצב HTTP 400 עם קוד שגיאה.

    קטע הקוד הבא של JavaScript מראה איך לבטל אסימון ב-JavaScript בלי להשתמש באופרטור ספריית הלקוח של Google APIs ל-JavaScript. מאז נקודת הקצה OAuth 2.0 של Google לביטול אין תמיכה בשיתוף משאבים בין מקורות (CORS), הקוד יוצר טופס ושולח את הטופס לנקודת הקצה (endpoint) במקום להשתמש בשיטה XMLHttpRequest() כדי לפרסם את הטופס בקשה.

    function revokeAccess(accessToken) {
      // Google's OAuth 2.0 endpoint for revoking access tokens.
      var revokeTokenEndpoint = 'https://oauth2.googleapis.com/revoke';
    
      // Create <form> element to use to POST data to the OAuth 2.0 endpoint.
      var form = document.createElement('form');
      form.setAttribute('method', 'post');
      form.setAttribute('action', revokeTokenEndpoint);
    
      // Add access token to the form so it is set as value of 'token' parameter.
      // This corresponds to the sample curl request, where the URL is:
      //      https://oauth2.googleapis.com/revoke?token={token}
      var tokenField = document.createElement('input');
      tokenField.setAttribute('type', 'hidden');
      tokenField.setAttribute('name', 'token');
      tokenField.setAttribute('value', accessToken);
      form.appendChild(tokenField);
    
      // Add form to page and submit it to actually revoke the token.
      document.body.appendChild(form);
      form.submit();
    }

    יישום הגנה על כל החשבונות

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

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

    • https://schemas.openid.net/secevent/risc/event-type/sessions-revoked
    • https://schemas.openid.net/secevent/oauth/event-type/token-revoked
    • https://schemas.openid.net/secevent/risc/event-type/account-disabled

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