במאמר הזה מוסבר איך להטמיע הרשאת OAuth 2.0 כדי לגשת לממשקי Google API מאפליקציית אינטרנט ב-JavaScript. פרוטוקול OAuth 2.0 מאפשר למשתמשים לשתף נתונים ספציפיים עם אפליקציה, תוך שמירה על הפרטיות של שמות המשתמשים, הסיסמאות ומידע אחר. לדוגמה, אפליקציה יכולה להשתמש ב-OAuth 2.0 כדי לקבל הרשאה מהמשתמשים לאחסן קבצים ב-Google Drive שלהם.
תהליך OAuth 2.0 הזה נקרא תהליך הענקת הרשאה משתמעת. הוא מיועד לאפליקציות שניגשות לממשקי API רק כשהמשתמש נמצא באפליקציה. האפליקציות האלה לא יכולות לאחסן מידע סודי.
בתהליך הזה, האפליקציה פותחת כתובת URL של Google שמשתמשת בפרמטרים של שאילתה כדי לזהות את האפליקציה ואת סוג הגישה ל-API שהאפליקציה דורשת. אפשר לפתוח את כתובת ה-URL בחלון הנוכחי של הדפדפן או בתיבת דו-שיח. המשתמש יכול לבצע אימות באמצעות Google ולהעניק את ההרשאות המבוקשות. לאחר מכן Google מפנה את המשתמש בחזרה לאפליקציה. ההפניה כוללת אסימון גישה, שהאפליקציה מאמתת ומשתמשת בו כדי לשלוח בקשות API.
ספריית הלקוח של Google APIs ו-Google Identity Services
אם אתם משתמשים בספריית הלקוח של Google APIs ל-JavaScript כדי לבצע קריאות מורשות ל-Google, אתם צריכים להשתמש בספריית JavaScript של Google Identity Services כדי לטפל בתהליך ההרשאה. אנחנו ממליצים מאוד להשתמש במודל הקוד של Google Identity Services, שמבוסס על תהליך ההרשאה באמצעות קוד המאובטח יותר עם PKCE.
דרישות מוקדמות
הפעלת ממשקי API בפרויקט
בכל אפליקציה ששולחת קריאות ל-Google APIs, צריך להפעיל את ממשקי ה-API האלה בקונסולה לממשקי API.
כדי להפעיל API בפרויקט:
- פותחים את ספריית ה-API ב-Google API Console.
- אם מתבקשים, בוחרים פרויקט או יוצרים פרויקט חדש.
- בספריית ה-API מופיעים כל ממשקי ה-API הזמינים, מקובצים לפי משפחת מוצרים ופופולריות. אם ה-API שרוצים להפעיל לא מופיע ברשימה, אפשר לחפש אותו או ללחוץ על View All במשפחת המוצרים שאליה הוא שייך.
- בוחרים את ה-API שרוצים להפעיל ולוחצים על הכפתור Enable.
- אם מוצגת בקשה, מפעילים את החיוב.
- אם מוצגת בקשה, קוראים את התנאים וההגבלות של ה-API ומאשרים אותם.
יצירת פרטי כניסה לאימות
כל אפליקציה שמשתמשת ב-OAuth 2.0 כדי לגשת ל-Google APIs צריכה פרטי כניסה לאימות שמזהים את האפליקציה בשרת OAuth 2.0 של Google. כך יוצרים פרטי כניסה לפרויקט: לאחר מכן, האפליקציות שלכם יוכלו להשתמש בפרטי הכניסה כדי לגשת לממשקי ה-API שהפעלתם בפרויקט.
- עוברים אל הדף "לקוחות".
- לוחצים על Create Client.
- בוחרים בסוג האפליקציה אפליקציית אינטרנט.
- ממלאים את הטופס. באפליקציות שמשתמשות ב-JavaScript כדי לשלוח בקשות מורשות ל-Google API, צריך לציין מקורות מורשים של JavaScript. המקורות מזהים את הדומיינים שמהם האפליקציה יכולה לשלוח בקשות לשרת OAuth 2.0. מקורות הנתונים האלה חייבים לעמוד בכללי האימות של Google.
זיהוי היקפי הגישה
היקפי ההרשאות מאפשרים לאפליקציה לבקש גישה רק למשאבים שהיא צריכה, וגם מאפשרים למשתמשים לקבוע את רמת הגישה שהם נותנים לאפליקציה. לכן, יכול להיות שיהיה קשר הפוך בין מספר היקפי ההרשאות שביקשתם לבין הסבירות שתקבלו את הסכמת המשתמש.
לפני שמתחילים להטמיע את ההרשאה של OAuth 2.0, מומלץ לזהות את היקפי ההרשאות שהאפליקציה תצטרך הרשאה כדי לגשת אליהם.
במסמך היקפי ההרשאות של OAuth 2.0 API מפורטת רשימה מלאה של היקפי ההרשאות שבהם אפשר להשתמש כדי לגשת לממשקי Google API.
איך מקבלים טוקני גישה מסוג OAuth 2.0
השלבים הבאים מראים איך האפליקציה יוצרת אינטראקציה עם שרת OAuth 2.0 של Google כדי לקבל את הסכמת המשתמש לביצוע בקשת API בשמו. האפליקציה חייבת לקבל את ההסכמה הזו לפני שהיא יכולה לבצע בקשת Google API שדורשת הרשאת משתמש.
שלב 1: הפניה לשרת OAuth 2.0 של Google
כדי לבקש הרשאת גישה לנתוני משתמש, צריך להפנות את המשתמש לשרת OAuth 2.0 של Google.
נקודות קצה (endpoints) של OAuth 2.0
יוצרים כתובת URL כדי לבקש גישה מנקודת הקצה של OAuth 2.0 של Google בכתובת https://accounts.google.com/o/oauth2/v2/auth. אפשר לגשת לנקודת הקצה הזו דרך HTTPS.
חיבורי HTTP רגילים נדחים.
שרת ההרשאות של Google תומך בפרמטרים הבאים של מחרוזת שאילתה לאפליקציות של שרת אינטרנט:
| פרמטרים | |||||||
|---|---|---|---|---|---|---|---|
client_id |
חובה
מזהה הלקוח של האפליקציה. הערך הזה מופיע בדף Clients במסוף Cloud. |
||||||
redirect_uri |
חובה
קובע לאן שרת ה-API מפנה את המשתמש אחרי שהוא משלים את תהליך ההרשאה. הערך חייב להיות זהה לאחד מכתובות ה-URI המורשות להפניה אוטומטית של לקוח OAuth 2.0, שהגדרתם בדף Clients במסוף Cloud של הלקוח. אם הערך הזה לא תואם ל-URI מורשה להפניה אוטומטית של ה- חשוב לשים לב שהסכמה |
||||||
response_type |
חובה
באפליקציות JavaScript צריך להגדיר את ערך הפרמטר ל- |
||||||
scope |
חובה
רשימה מופרדת ברווחים של היקפי הרשאות שמזהים את המשאבים שהאפליקציה יכולה לגשת אליהם בשם המשתמש. הערכים האלה משמשים את מסך ההסכמה ש-Google מציגה למשתמש. היקפי ההרשאות מאפשרים לאפליקציה לבקש גישה רק למשאבים שהיא צריכה, וגם מאפשרים למשתמשים לשלוט ברמת הגישה שהם נותנים לאפליקציה. לכן, יש קשר הפוך בין מספר ההיקפים המבוקשים לבין הסבירות לקבלת הסכמה מהמשתמש. מומלץ שהאפליקציה תבקש גישה להיקפי הרשאות בהקשר, כשאפשר. כשמבקשים גישה לנתוני משתמשים בהקשר המתאים, באמצעות הרשאה מצטברת, עוזרים למשתמשים להבין למה האפליקציה צריכה את הגישה שהיא מבקשת. |
||||||
state |
מומלץ
מציין ערך מחרוזת כלשהו שהאפליקציה משתמשת בו כדי לשמור על המצב בין בקשת ההרשאה לבין התגובה של שרת ההרשאות.
השרת מחזיר את הערך המדויק ששלחתם כצמד אפשר להשתמש בפרמטר הזה למספר מטרות, כמו הפניית המשתמש למשאב הנכון באפליקציה, שליחת מספרים חד-פעמיים (nonce) והפחתת זיוף בקשות בין אתרים. מכיוון שאפשר לנחש את |
||||||
include_granted_scopes |
אופציונלי
מאפשר לאפליקציות להשתמש בהרשאה מצטברת כדי לבקש גישה להיקפים נוספים בהקשר. אם מגדירים את הערך של הפרמטר הזה כ- |
||||||
enable_granular_consent |
אופציונלי
ברירת המחדל היא כש-Google תפעיל הרשאות פרטניות לאפליקציה, הפרמטר הזה לא ישפיע יותר. |
||||||
login_hint |
אופציונלי
אם האפליקציה יודעת איזה משתמש מנסה לבצע אימות, היא יכולה להשתמש בפרמטר הזה כדי לספק רמז לשרת האימות של Google. השרת משתמש ברמז כדי לפשט את תהליך ההתחברות, על ידי מילוי מראש של שדה האימייל בטופס הכניסה או על ידי בחירת הסשן המתאים של ריבוי התחברויות. מגדירים את ערך הפרמטר לכתובת אימייל או למזהה |
||||||
prompt |
אופציונלי
רשימה של הנחיות שמוצגות למשתמש, מופרדות ברווחים ותלויות אותיות רישיות. אם לא מציינים את הפרמטר הזה, המשתמש יתבקש רק בפעם הראשונה שהפרויקט מבקש גישה. מידע נוסף זמין במאמר בקשה להסכמה מחדש. הערכים שאפשר לבחור הם:
|
||||||
הפניה לדוגמה לשרת ההרשאות של Google
לפניכם כתובת URL לדוגמה, עם מעברי שורה ורווחים כדי שיהיה קל יותר לקרוא אותה.
https://accounts.google.com/o/oauth2/v2/auth? scope=https%3A//www.googleapis.com/auth/drive.metadata.readonly%20https%3A//www.googleapis.com/auth/calendar.readonly& include_granted_scopes=true& response_type=token& state=state_parameter_passthrough_value& redirect_uri=https%3A//developers.google.com/oauthplayground& client_id=client_id
אחרי שיוצרים את כתובת ה-URL של הבקשה, מפנים אליה את המשתמש.
קוד לדוגמה ב-JavaScript
קטע הקוד הבא ב-JavaScript מראה איך להתחיל את תהליך ההרשאה ב-JavaScript בלי להשתמש בספריית הלקוח של Google APIs ל-JavaScript. מכיוון שנקודת הקצה (endpoint) הזו של 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 https://www.googleapis.com/auth/calendar.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
נקודת הקצה לאימות מוצגת בתוך סוכן משתמש מוטמע שאסור להשתמש בו לפי המדיניות של Google בנושא OAuth 2.0.
מפתחים ב-iOS וב-macOS עלולים להיתקל בשגיאה הזו כשהם פותחים בקשות הרשאה ב-WKWebView.
במקום זאת, המפתחים צריכים להשתמש בספריות iOS כמו כניסה באמצעות חשבון Google ל-iOS או AppAuth ל-iOS של OpenID Foundation.
מפתחי אתרים עשויים להיתקל בשגיאה הזו כשאפליקציה ל-iOS או ל-macOS פותחת קישור כללי לדף אינטרנט אחר בסוכן משתמש מוטמע, והמשתמש עובר לנקודת הקצה של Google לאימות באמצעות OAuth 2.0 מהאתר שלכם. המפתחים צריכים לאפשר פתיחה של קישורים כלליים בכלי לטיפול בקישורים שמוגדר כברירת מחדל במערכת ההפעלה, כולל כלים לטיפול בקישורים אוניברסליים או אפליקציית הדפדפן שמוגדרת כברירת מחדל. גם הספרייה SFSafariViewController היא אפשרות נתמכת.
org_internal
מזהה הלקוח ב-OAuth בבקשה הוא חלק מפרויקט שמגביל את הגישה לחשבונות Google בארגון ספציפי ב-Google Cloud. למידע נוסף על אפשרות ההגדרה הזו, קראו את הקטע סוג משתמש במאמר העזרה בנושא הגדרת מסך ההסכמה ל-OAuth.
invalid_client
המקור שממנו נשלחה הבקשה לא מורשה ללקוח הזה. origin_mismatch.
deleted_client
לקוח OAuth שמשמש לשליחת הבקשה נמחק. המחיקה יכולה להתבצע באופן ידני או אוטומטי במקרה של לקוחות שלא בשימוש. אפשר לשחזר לקוחות שנמחקו תוך 30 יום ממועד המחיקה. מידע נוסף
invalid_grant
כשמשתמשים בהרשאה מצטברת, יכול להיות שהתוקף של האסימון פג או שהוא בוטל. מאמתים שוב את המשתמש ומבקשים ממנו הסכמה מהמשתמש לקבלת אסימונים חדשים. אם השגיאה הזו ממשיכה להופיע, צריך לוודא שהאפליקציה הוגדרה בצורה נכונה ושהבקשה כוללת את האסימונים והפרמטרים הנכונים. אם לא, יכול להיות שחשבון המשתמש נמחק או הושבת.
origin_mismatch
יכול להיות שהסכימה, הדומיין ו/או היציאה של ה-JavaScript שממנו נשלחה בקשת ההרשאה לא תואמים ל-URI של מקור JavaScript מורשה שרשום במזהה הלקוח ב-OAuth. בודקים את מקורות ה-JavaScript המורשים בדף Clients במסוף Google Cloud.
redirect_uri_mismatch
הערך של redirect_uri שהועבר בבקשת ההרשאה לא תואם לכתובת URI מורשית להפניה אוטומטית של מזהה הלקוח ב-OAuth. בודקים את כתובות ה-URI המורשות להפניה אוטומטית בדף Clients במסוף Google Cloud.
יכול להיות שהסכימה, הדומיין ו/או היציאה של ה-JavaScript שממנו נשלחה בקשת ההרשאה לא תואמים ל-URI של מקור JavaScript מורשה שרשום במזהה הלקוח ב-OAuth. בודקים את מקורות ה-JavaScript המורשים בדף Clients במסוף Google Cloud.
יכול להיות שהפרמטר redirect_uri מתייחס לתהליך OAuth מחוץ לתחום (OOB) שהוצא משימוש ולא נתמך יותר. כדי לעדכן את השילוב, צריך לפעול לפי המדריך להעברת נתונים (מיגרציה).
invalid_request
הייתה בעיה בבקשה ששלחת. יכולות להיות לכך כמה סיבות:
- הפורמט של הבקשה לא היה תקין
- בבקשה חסרים פרמטרים נדרשים
- הבקשה משתמשת בשיטת הרשאה ש-Google לא תומכת בה. מוודאים ששילוב ה-OAuth משתמש בשיטת שילוב מומלצת
שלב 3: טיפול בתגובה של שרת OAuth 2.0
נקודות קצה (endpoints) של 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 וגישה לקריאה בלבד כדי להציג את האירועים שלכם ביומן Google:
https://accounts.google.com/o/oauth2/v2/auth? scope=https%3A//www.googleapis.com/auth/drive.metadata.readonly%20https%3A//www.googleapis.com/auth/calendar.readonly& include_granted_scopes=true& response_type=token& state=state_parameter_passthrough_value& redirect_uri=https%3A//developers.google.com/oauthplayground& client_id=client_id
אחרי שתסיימו את תהליך האימות באמצעות OAuth 2.0, הדפדפן יפנה אתכם אל OAuth 2.0 Playground, כלי לבדיקת תהליכי OAuth. תראו ש-OAuth 2.0 Playground תיעד באופן אוטומטי את קוד ההרשאה.
שלב 4: בודקים אילו היקפי הרשאות המשתמשים נתנו
כשמבקשים כמה הרשאות (היקפים), יכול להיות שהמשתמשים לא יתנו לאפליקציה גישה לכולן. האפליקציה צריכה לאמת אילו היקפי הרשאות ניתנו בפועל, ולטפל בצורה חלקה במצבים שבהם חלק מההרשאות נדחו, בדרך כלל על ידי השבתת התכונות שמסתמכות על היקפי ההרשאות שנדחו.
אבל יש מקרים חריגים. אפליקציות של Google Workspace Enterprise עם הענקת גישה ברמת הדומיין, או אפליקציות שמסומנות כמהימנות, עוקפות את מסך ההסכמה להרשאות פרטניות. באפליקציות האלה, המשתמשים לא יראו את מסך ההסכמה להרשאות פרטניות. במקום זאת, האפליקציה תקבל את כל ההיקפים המבוקשים או לא תקבל אף אחד מהם.
מידע נוסף זמין במאמר איך מטפלים בהרשאות פרטניות.
נקודות קצה (endpoints) של OAuth 2.0
כדי לבדוק אם המשתמש נתן לאפליקציה גישה להיקף מסוים, בודקים את השדה scope בתגובה של אסימון הגישה. היקפי הגישה שניתנו על ידי טוקן הגישה, מבוטאים כרשימה של מחרוזות תלויות אותיות רישיות, שמופרדות ברווחים.
לדוגמה, התגובה הבאה לדוגמה של אסימון גישה מציינת שהמשתמש העניק לאפליקציה גישה להרשאות לקריאה בלבד של פעילות ב-Drive ואירועים ביומן:
{ "access_token": "1/fFAGRNJru1FTz70BzhT3Zg", "expires_in": 3920, "token_type": "Bearer", "scope": "https://www.googleapis.com/auth/drive.metadata.readonly https://www.googleapis.com/auth/calendar.readonly", "refresh_token": "1//xEoDL4iW3cxlI7yDbSRFYNG01kVKM2C-259HOF2aQbI" }
שליחת קריאה ל-Google APIs
נקודות קצה (endpoints) של OAuth 2.0
אחרי שהאפליקציה מקבלת טוקן גישה, אתם יכולים להשתמש בו כדי לשלוח קריאות ל-Google API בשם חשבון משתמש מסוים, אם הוענקו היקפי הגישה שנדרשים ל-API. כדי לעשות את זה, צריך לכלול את טוקן הגישה בבקשה ל-API, על ידי הוספה של פרמטר השאילתה access_token או של ערך Bearer בכותרת ה-HTTP Authorization. כשאפשר, עדיף להשתמש בכותרת HTTP, כי מחרוזות של שאילתות נוטות להופיע ביומני השרת. ברוב המקרים אפשר להשתמש בספריית לקוח כדי להגדיר את הקריאות ל-Google APIs (לדוגמה, כשקוראים ל-Drive Files API).
אתם יכולים לנסות את כל ממשקי ה-API של Google ולראות את היקפי ההרשאות שלהם ב-OAuth 2.0 Playground.
דוגמאות ל-HTTP GET
קריאה לנקודת הקצה (endpoint)
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);
דוגמה פתורה
נקודות קצה (endpoints) של OAuth 2.0
דוגמת הקוד הזו ממחישה איך להשלים את תהליך OAuth 2.0 ב-JavaScript בלי להשתמש בספריית הלקוח של Google APIs ל-JavaScript. הקוד מיועד לדף HTML שמוצג בו כפתור לניסיון של בקשת API. אם לוחצים על הכפתור, הקוד בודק אם הדף שמר טוקן גישה ל-API באחסון המקומי של הדפדפן. אם כן, הוא מבצע את בקשת ה-API. אחרת, הוא מתחיל את תהליך OAuth 2.0.
בתהליך הרשאה באמצעות OAuth 2.0, הדף מבצע את השלבים הבאים:
- היא מפנה את המשתמש לשרת OAuth 2.0 של Google, שמבקש גישה להיקפי ההרשאות
https://www.googleapis.com/auth/drive.metadata.readonlyו-https://www.googleapis.com/auth/calendar.readonly. - אחרי שהמשתמש מעניק (או דוחה) גישה להיקף הרשאות אחד או יותר, הוא מופנה חזרה לדף המקורי, שמנתח את אסימון הגישה ממחרוזת מזהה המקטע.
- בדף הזה אפשר לבדוק לאילו היקפי הרשאות המשתמש נתן לאפליקציה גישה.
אם המשתמש העניק גישה להיקפים המבוקשים, הדף משתמש באסימון הגישה כדי לשלוח את בקשת ה-API לדוגמה.
בקשת ה-API מפעילה את ה-method
about.getשל Drive API כדי לאחזר מידע על חשבון Google Drive של המשתמש המורשה.- אם הבקשה בוצעה בהצלחה, התגובה מה-API מתועדת במסוף ניפוי הבאגים של הדפדפן.
אתם יכולים לבטל את הגישה לאפליקציה דרך הדף הרשאות בחשבון Google. האפליקציה מופיעה בשם שצוין בדף המיתוג במסך ההסכמה ל-OAuth במהלך יצירת מזהה הלקוח.
כדי להריץ את הקוד הזה באופן מקומי, צריך להגדיר ערכים למשתנים YOUR_CLIENT_ID ו-YOUR_REDIRECT_URI שתואמים לפרטי הכניסה לאימות. המשתנה YOUR_REDIRECT_URI צריך להיות מוגדר לאותה כתובת URL שבה הדף מוצג. הערך חייב להיות זהה לאחד ממזהי ה-URI המורשים להפניה אוטומטית של לקוח OAuth 2.0, שהגדרתם בדף Clients במסוף Cloud. אם הערך הזה לא תואם ל-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']) {
// User authorized the request. Now, check which scopes were granted.
if (params['scope'].includes('https://www.googleapis.com/auth/drive.metadata.readonly')) {
// User authorized read-only Drive activity permission.
// Calling the APIs, etc.
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 {
// User didn't authorize read-only Drive activity permission.
// Update UX and application accordingly
console.log('User did not authorize read-only Drive activity permission.');
}
// Check if user authorized Calendar read permission.
if (params['scope'].includes('https://www.googleapis.com/auth/calendar.readonly')) {
// User authorized Calendar read permission.
// Calling the APIs, etc.
console.log('User authorized Calendar read permission.');
}
else {
// User didn't authorize Calendar read permission.
// Update UX and application accordingly
console.log('User did not authorize Calendar read permission.');
}
} 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 https://www.googleapis.com/auth/calendar.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 חייבים לעמוד בכללים האלה. בסעיף 3 של RFC 3986 מפורטות ההגדרות של דומיין, מארח וסכימה, שמשמשות בכללים האלה.
| כללי אימות | |
|---|---|
| Scheme |
מקורות JavaScript חייבים להשתמש בסכימת HTTPS, ולא ב-HTTP רגיל. מזהי URI של מארח מקומי (כולל מזהי URI של כתובות IP של מארח מקומי) פטורים מהכלל הזה. |
| מארח |
המארחים לא יכולים להיות כתובות IP גולמיות. כתובות IP של מארח מקומי פטורות מהכלל הזה. |
| דומיין |
“googleusercontent.com”.goo.gl)
אלא אם הדומיין בבעלות האפליקציה. |
| Userinfo |
מקורות JavaScript לא יכולים להכיל את רכיב המשנה userinfo. |
| נתיב |
מקורות JavaScript לא יכולים להכיל את רכיב הנתיב. |
| שאילתה |
מקורות JavaScript לא יכולים להכיל את רכיב השאילתה. |
| Fragment |
מקורות JavaScript לא יכולים להכיל את רכיב המקטע. |
| דמויות |
מקורות JavaScript לא יכולים להכיל תווים מסוימים, כולל:
|
הרשאה מצטברת
בפרוטוקול OAuth 2.0, האפליקציה מבקשת הרשאה לגשת למשאבים שמזוהים לפי היקפי הרשאות. כדי לספק חוויית משתמש טובה, מומלץ לבקש הרשאה למשאבים בזמן שבו אתם צריכים אותם. כדי לאפשר את זה, שרת ההרשאות של Google תומך בהרשאה מצטברת. התכונה הזו מאפשרת לבקש היקפי הרשאות לפי הצורך. אם המשתמש מעניק הרשאה להיקף ההרשאות החדש, התכונה מחזירה קוד הרשאה שאפשר להחליף באסימון שמכיל את כל היקפי ההרשאות שהמשתמש העניק לפרויקט.
לדוגמה, אפליקציה שמאפשרת לאנשים לדגום טראקי מוזיקה וליצור מיקסים עשויה לדרוש מעט מאוד משאבים בזמן הכניסה, אולי רק את שם המשתמש. אבל כדי לשמור את המיקס המוגמר, צריך גישה ל-Google Drive של המשתמש. רוב האנשים ירגישו שזה טבעי אם הם יתבקשו לתת גישה ל-Google Drive רק כשהאפליקציה באמת תצטרך את זה.
במקרה כזה, בזמן הכניסה האפליקציה עשויה לבקש את ההיקפים openid ו-profile כדי לבצע כניסה בסיסית, ואז לבקש את ההיקף https://www.googleapis.com/auth/drive.file בזמן הבקשה הראשונה לשמירת מיקס.
הכללים הבאים חלים על אסימון גישה שמתקבל מהרשאה מצטברת:
- אפשר להשתמש באסימון כדי לגשת למשאבים שתואמים לכל אחד מההיקפים שנכללים בהרשאה החדשה והמשולבת.
- כשמשתמשים בטוקן הרענון של ההרשאה המשולבת כדי לקבל טוקן גישה, טוקן הגישה מייצג את ההרשאה המשולבת ואפשר להשתמש בו לכל אחד מערכי ה-
scopeשכלולים בתגובה. - ההרשאה המשולבת כוללת את כל ההיקפים שהמשתמש העניק לפרויקט ה-API, גם אם ההרשאות התבקשו מלקוחות שונים. לדוגמה, אם משתמש נתן גישה להיקף הרשאות אחד באמצעות אפליקציית לקוח למחשב, ואז נתן גישה להיקף הרשאות אחר לאותה אפליקציה באמצעות אפליקציית לקוח לנייד, ההרשאה המשולבת תכלול את שני היקפי ההרשאות.
- אם מבטלים טוקן שמייצג הרשאה משולבת, הגישה לכל היקפי ההרשאות של אותה הרשאה בשם המשתמש המשויך מבוטלת בו-זמנית.
דוגמאות הקוד הבאות מראות איך להוסיף היקפים לטוקן גישה קיים. כך האפליקציה לא צריכה לנהל כמה טוקני גישה.
נקודות קצה (endpoints) של OAuth 2.0
כדי להוסיף היקפי הרשאות לטוקן גישה קיים, צריך לכלול את הפרמטר include_granted_scopes בבקשה לשרת OAuth 2.0 של Google.
בקטע הקוד הבא אפשר לראות איך עושים את זה. בקטע הקוד הזה, ההנחה היא ששמרתם את היקפי ההרשאות שתקפים לטוקן הגישה שלכם באחסון המקומי של הדפדפן. (הקוד של הדוגמה המלאה שומר רשימה של היקפי הרשאות שבהם טוקן הגישה תקף, על ידי הגדרת המאפיין oauth2-test-params.scope באחסון המקומי של הדפדפן).
קטע הקוד משווה בין ההיקפים שבהם אסימון הגישה תקף לבין ההיקף שבו רוצים להשתמש בשאילתה מסוימת. אם אסימון הגישה לא מכסה את ההיקף הזה, הרשאה באמצעות 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. }
ביטול טוקן
במקרים מסוימים, משתמשים עשויים לרצות לבטל את הגישה שניתנה לאפליקציה. המשתמש יכול לבטל את הגישה דרך הגדרות החשבון. מידע נוסף זמין במאמר התמיכה הסרת הגישה של אתר או אפליקציה לחשבון שלכם.
אפליקציה יכולה גם לבטל באופן פרוגרמטי את הגישה שניתנה לה. ביטול הרשאות באופן פרוגרמטי חשוב במקרים שבהם משתמש מבטל מינוי, מסיר אפליקציה או כשמשאבי ה-API שנדרשים לאפליקציה השתנו באופן משמעותי. במילים אחרות, חלק מתהליך ההסרה יכול לכלול בקשת API כדי לוודא שההרשאות שניתנו לאפליקציה בעבר הוסרו.
נקודות קצה (endpoints) של 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. מכיוון שנקודת הקצה של Google OAuth 2.0 לביטול אסימונים לא תומכת בשיתוף משאבים בין מקורות שונים (CORS), הקוד יוצר טופס ושולח אותו לנקודת הקצה במקום להשתמש ב-method 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
במאמר הגנה על חשבונות משתמשים באמצעות הגנה על כל החשבונות מוסבר איך להטמיע את ההגנה על כל החשבונות, ויש בו רשימה מלאה של האירועים הזמינים.