שימוש ב-OAuth 2.0 לאפליקציות אינטרנט

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

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

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

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

ספריות לקוח

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

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

ספריות הלקוח של Google API לאפליקציות בצד השרת זמינות בשפות הבאות:

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

הפעלת ממשקי 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 client ID.
  3. בוחרים את סוג האפליקציה Web application.
  4. ממלאים את הטופס ולוחצים על יצירה. באפליקציות שמשתמשות בשפות ובמסגרות כמו PHP, Java, Python, Ruby ו-NET., חובה לציין URIs מורשים להפניה אוטומטית. מזהי ה-URI של ההפניה האוטומטית הם נקודות הקצה שאליהן שרת OAuth 2.0 יכול לשלוח תשובות. נקודות הקצה האלה חייבות לעמוד בכללי האימות של Google.

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

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

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

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

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

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

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

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

דרישות ספציפיות לשפה

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

PHP‏

כדי להריץ את דוגמאות קוד ה-PHP במסמך הזה, צריך:

  • PHP 5.6 ומעלה עם ממשק שורת הפקודה (CLI) ותוסף JSON מותקן.
  • הכלי לניהול תלות של Composer.
  • ספריית הלקוח של Google APIs עבור PHP:

    composer require google/apiclient:^2.10

Python

כדי להריץ את הדוגמאות של קוד Python במסמך הזה, צריך:

  • Python 2.6 ואילך
  • כלי לניהול חבילות pip.
  • ספריית הלקוח של Google APIs ל-Python:
    pip install --upgrade google-api-python-client
  • google-auth, google-auth-oauthlib ו-google-auth-httplib2 עבור הרשאת משתמש.
    pip install --upgrade google-auth google-auth-oauthlib google-auth-httplib2
  • תוכנת האינטרנט של Flask Python.
    pip install --upgrade flask
  • ספריית ה-HTTP של requests.
    pip install --upgrade requests

Ruby

כדי להריץ את דוגמאות הקוד של Ruby במסמך הזה, צריך:

  • Ruby 2.6 ומעלה
  • ספריית Google Auth עבור Ruby:

    gem install googleauth
  • תוכנת האינטרנט של Synatra Ruby.

    gem install sinatra

Node.js

כדי להריץ את דוגמאות הקוד של Node.js במסמך הזה, צריך:

  • LTS התחזוקה, ה-LTS הפעיל או הגרסה הנוכחית של Node.js.
  • לקוח Google APIs Node.js:

    npm install googleapis

HTTP/REST

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

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

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

הרשימה הבאה מסכמת את השלבים הבאים:

  1. האפליקציה מזהה את ההרשאות הנדרשות.
  2. האפליקציה מפנה את המשתמשים ל-Google יחד עם רשימת ההרשאות הנדרשות.
  3. המשתמש מחליט אם להעניק את ההרשאות לאפליקציה.
  4. האפליקציה שלך מגלה מה המשתמש החליט.
  5. אם המשתמש העניק את ההרשאות הנדרשות, האפליקציה מאחזרת את האסימונים הדרושים לשליחת בקשות API בשמו.

שלב 1: הגדרת פרמטרים של הרשאות

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

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

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

PHP‏

קטע הקוד הבא יוצר אובייקט Google\Client(), שמגדיר את הפרמטרים בבקשת ההרשאה.

האובייקט הזה משתמש במידע מהקובץ client_secret.json כדי לזהות את האפליקציה שלכם. (למידע נוסף על הקובץ, עיינו במאמר יצירת פרטי כניסה להרשאה). האובייקט מזהה גם את היקפי ההרשאות שהאפליקציה מבקשת הרשאת גישה אליהם, ואת כתובת ה-URL של נקודת הקצה לאימות של האפליקציה, שיטפלו בתגובה משרת OAuth 2.0 של Google. לבסוף, הקוד מגדיר את הפרמטרים האופציונליים access_type ו-include_granted_scopes.

לדוגמה, הקוד הזה מבקש גישה לקריאה בלבד, במצב אופליין, ל-Google Drive של המשתמש:

$client = new Google\Client();
$client->setAuthConfig('client_secret.json');
$client->addScope(Google\Service\Drive::DRIVE_METADATA_READONLY);
$client->setRedirectUri('http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback.php');
// offline access will give you both an access and refresh token so that
// your app can refresh the access token without user interaction.
$client->setAccessType('offline');
// Using "consent" will prompt the user for consent
$client->setPrompt('consent');
$client->setIncludeGrantedScopes(true);   // incremental auth

בבקשה מפורטים הפרטים הבאים:

פרמטרים
client_id נדרש

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

ב-PHP, קוראים לפונקציה setAuthConfig כדי לטעון פרטי כניסה להרשאה מקובץ client_secret.json.

$client = new Google\Client();
$client->setAuthConfig('client_secret.json');
redirect_uri נדרש

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

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

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

$client->setRedirectUri('https://oauth2.example.com/code');
scope נדרש

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

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

כדי להגדיר את הערך הזה ב-PHP, צריך להפעיל את הפונקציה addScope:

$client->addScope(Google\Service\Drive::DRIVE_METADATA_READONLY);

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

access_type מומלץ

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

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

כדי להגדיר את הערך הזה ב-PHP, צריך להפעיל את הפונקציה setAccessType:

$client->setAccessType('offline');
state מומלץ

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

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

כדי להגדיר את הערך הזה ב-PHP, צריך להפעיל את הפונקציה setState:

$client->setState($sample_passthrough_value);
include_granted_scopes אופציונלי

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

כדי להגדיר את הערך הזה ב-PHP, צריך להפעיל את הפונקציה setIncludeGrantedScopes:

$client->setIncludeGrantedScopes(true);
login_hint אופציונלי

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

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

כדי להגדיר את הערך הזה ב-PHP, צריך להפעיל את הפונקציה setLoginHint:

$client->setLoginHint('None');
prompt אופציונלי

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

כדי להגדיר את הערך הזה ב-PHP, צריך להפעיל את הפונקציה setPrompt:

$client->setPrompt('consent');

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

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

Python

קטע הקוד הבא משתמש במודול google-auth-oauthlib.flow כדי לבנות את בקשת ההרשאה.

הקוד בונה אובייקט Flow, שמזהה את האפליקציה באמצעות מידע מהקובץ client_secret.json שהורדתם אחרי יצירת פרטי כניסה להרשאה. האובייקט הזה מזהה גם את היקפי ההרשאות שהאפליקציה מבקשת הרשאת גישה אליהם, ואת כתובת ה-URL של נקודת הקצה לאימות של האפליקציה, שיטפלו בתגובה משרת OAuth 2.0 של Google. לבסוף, הקוד מגדיר את הפרמטרים האופציונליים access_type ו-include_granted_scopes.

לדוגמה, הקוד הזה מבקש גישה לקריאה בלבד, במצב אופליין, ל-Google Drive של המשתמש:

import google.oauth2.credentials
import google_auth_oauthlib.flow

# Use the client_secret.json file to identify the application requesting
# authorization. The client ID (from that file) and access scopes are required.
flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
    'client_secret.json',
    scopes=['https://www.googleapis.com/auth/drive.metadata.readonly'])

# Indicate where the API server will redirect the user after the user completes
# the authorization flow. The redirect URI is required. The value must exactly
# match one of the authorized redirect URIs for the OAuth 2.0 client, which you
# configured in the API Console. If this value doesn't match an authorized URI,
# you will get a 'redirect_uri_mismatch' error.
flow.redirect_uri = 'https://www.example.com/oauth2callback'

# Generate URL for request to Google's OAuth 2.0 server.
# Use kwargs to set optional request parameters.
authorization_url, state = flow.authorization_url(
    # Enable offline access so that you can refresh an access token without
    # re-prompting the user for permission. Recommended for web server apps.
    access_type='offline',
    # Enable incremental authorization. Recommended as a best practice.
    include_granted_scopes='true')

בבקשה מפורטים הפרטים הבאים:

פרמטרים
client_id נדרש

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

ב-Python, קוראים ל-method from_client_secrets_file כדי לאחזר את מזהה הלקוח מקובץ client_secret.json. (אפשר גם להשתמש בשיטה from_client_config, שמעבירה את הגדרת הלקוח כפי שהיא הופיעה במקור בקובץ סודות לקוח, אבל לא ניגשת לקובץ עצמו).

flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
    'client_secret.json',
    scopes=['https://www.googleapis.com/auth/drive.metadata.readonly'])
redirect_uri נדרש

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

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

כדי להגדיר את הערך הזה ב-Python, צריך להגדיר את מאפיין redirect_uri של האובייקט flow:

flow.redirect_uri = 'https://oauth2.example.com/code'
scope נדרש

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

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

ב-Python, משתמשים באותה שיטה שבה משתמשים כדי להגדיר את client_id כדי לציין את רשימת ההיקפים.

flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
    'client_secret.json',
    scopes=['https://www.googleapis.com/auth/drive.metadata.readonly'])

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

access_type מומלץ

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

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

ב-Python, מגדירים את הפרמטר access_type על ידי ציון הערך access_type כארגומנט של מילת מפתח כשקוראים ל-method flow.authorization_url:

authorization_url, state = flow.authorization_url(
    access_type='offline',
    include_granted_scopes='true')
state מומלץ

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

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

ב-Python, מגדירים את הפרמטר state על ידי ציון הערך state כארגומנט של מילת מפתח כשקוראים לשיטה flow.authorization_url:

authorization_url, state = flow.authorization_url(
    access_type='offline',
    state=sample_passthrough_value,
    include_granted_scopes='true')
include_granted_scopes אופציונלי

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

ב-Python, מגדירים את הפרמטר include_granted_scopes על ידי ציון הערך include_granted_scopes כארגומנט של מילת מפתח כשקוראים ל-method flow.authorization_url:

authorization_url, state = flow.authorization_url(
    access_type='offline',
    include_granted_scopes='true')
login_hint אופציונלי

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

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

ב-Python, מגדירים את הפרמטר login_hint על ידי ציון הערך login_hint כארגומנט של מילת מפתח כשקוראים ל-method flow.authorization_url:

authorization_url, state = flow.authorization_url(
    access_type='offline',
    login_hint='None',
    include_granted_scopes='true')
prompt אופציונלי

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

ב-Python, מגדירים את הפרמטר prompt על ידי ציון הערך prompt כארגומנט של מילת מפתח כשקוראים לשיטה flow.authorization_url:

authorization_url, state = flow.authorization_url(
      access_type='offline',
      prompt='consent',
      include_granted_scopes='true')

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

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

Ruby

צריך להשתמש בקובץ client_secrets.json שיצרתם כדי להגדיר אובייקט לקוח באפליקציה. כשמגדירים אובייקט לקוח, מציינים את היקפי ההרשאות שהאפליקציה צריכה לגשת אליהם, יחד עם כתובת ה-URL של נקודת הקצה (endpoint) של ההרשאה של האפליקציה, שתטפל בתגובה משרת OAuth 2.0.

לדוגמה, הקוד הזה מבקש גישה לקריאה בלבד, במצב אופליין, ל-Google Drive של המשתמש:

require 'google/apis/drive_v3'
require "googleauth"
require 'googleauth/stores/redis_token_store'

client_id = Google::Auth::ClientId.from_file('/path/to/client_secret.json')
scope = 'https://www.googleapis.com/auth/drive.metadata.readonly'
token_store = Google::Auth::Stores::RedisTokenStore.new(redis: Redis.new)
authorizer = Google::Auth::WebUserAuthorizer.new(client_id, scope, token_store, '/oauth2callback')

Your application uses the client object to perform OAuth 2.0 operations, such as generating authorization request URLs and applying access tokens to HTTP requests.

Node.js

The code snippet below creates a google.auth.OAuth2 object, which defines the parameters in the authorization request.

That object uses information from your client_secret.json file to identify your application. To ask for permissions from a user to retrieve an access token, you redirect them to a consent page. To create a consent page URL:

const {google} = require('googleapis');

/**
 * To use OAuth2 authentication, we need access to a CLIENT_ID, CLIENT_SECRET, AND REDIRECT_URI
 * from the client_secret.json file. To get these credentials for your application, visit
 * https://console.cloud.google.com/apis/credentials.
 */
const oauth2Client = new google.auth.OAuth2(
  YOUR_CLIENT_ID,
  YOUR_CLIENT_SECRET,
  YOUR_REDIRECT_URL
);

// Access scopes for read-only Drive activity.
const scopes = [
  'https://www.googleapis.com/auth/drive.metadata.readonly'
];

// Generate a url that asks permissions for the Drive activity scope
const authorizationUrl = oauth2Client.generateAuthUrl({
  // 'online' (default) or 'offline' (gets refresh_token)
  access_type: 'offline',
  /** Pass in the scopes array defined above.
    * Alternatively, if only one scope is needed, you can pass a scope URL as a string */
  scope: scopes,
  // Enable incremental authorization. Recommended as a best practice.
  include_granted_scopes: true
});

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

HTTP/REST

נקודת הקצה של 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 נדרש

המדיניות קובעת אם נקודת הקצה של Google OAuth 2.0 תחזיר קוד הרשאה.

צריך להגדיר את ערך הפרמטר כ-code לאפליקציות של שרת אינטרנט.

scope נדרש

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

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

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

access_type מומלץ

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

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

state מומלץ

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

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

include_granted_scopes אופציונלי

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

login_hint אופציונלי

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

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

prompt אופציונלי

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

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

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

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

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

PHP‏

  1. יוצרים כתובת URL כדי לבקש גישה משרת OAuth 2.0 של Google:
    $auth_url = $client->createAuthUrl();
  2. הפניה אוטומטית של המשתמש אל $auth_url:
    header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));

Python

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

return flask.redirect(authorization_url)

Ruby

  1. יוצרים כתובת URL כדי לבקש גישה משרת OAuth 2.0 של Google:
    auth_uri = authorizer.get_authorization_url(login_hint: user_id, request: request)
  2. יש להפנות את המשתמש אל auth_uri.

Node.js

  1. משתמשים בכתובת ה-URL שנוצרה authorizationUrl משלב 1 generateAuthUrl כדי לבקש גישה משרת OAuth 2.0 של Google.
  2. יש להפנות את המשתמש אל authorizationUrl.
    res.writeHead(301, { "Location": authorizationUrl });

HTTP/REST

Sample redirect to Google's authorization server

An example URL is shown below, with line breaks and spaces for readability.

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

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

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

שלב 3: 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

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

Android

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

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

iOS

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

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

org_internal

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

invalid_client

סוד הלקוח ב-OAuth שגוי. צריך לבדוק את ההגדרה של לקוח OAuth, כולל מזהה הלקוח והסוד ששימשו לבקשה הזו.

invalid_grant

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

redirect_uri_mismatch

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

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

invalid_request

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

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

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

שרת OAuth 2.0 מגיב לבקשת הגישה של האפליקציה באמצעות כתובת ה-URL שצוינה בבקשה.

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

תגובה עם שגיאה:

https://oauth2.example.com/auth?error=access_denied

תשובה עם קוד הרשאה:

https://oauth2.example.com/auth?code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7

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

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

https://accounts.google.com/o/oauth2/v2/auth?
 scope=https%3A//www.googleapis.com/auth/drive.metadata.readonly&
 access_type=offline&
 include_granted_scopes=true&
 response_type=code&
 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 כשהמשתמש מופנה חזרה לאפליקציה.

שלב 5: החלפת קוד ההרשאה של אסימוני רענון וגישה

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

PHP‏

כדי להחליף קוד הרשאה באסימון גישה, צריך להשתמש בשיטה authenticate:

$client->authenticate($_GET['code']);

ניתן לאחזר את אסימון הגישה באמצעות השיטה getAccessToken:

$access_token = $client->getAccessToken();

Python

בדף ההתקשרות חזרה, משתמשים בספרייה google-auth כדי לאמת את התגובה של שרת ההרשאות. לאחר מכן משתמשים בשיטה flow.fetch_token כדי להחליף את קוד ההרשאה בתשובה הזו באסימון גישה:

state = flask.session['state']
flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
    'client_secret.json',
    scopes=['https://www.googleapis.com/auth/drive.metadata.readonly'],
    state=state)
flow.redirect_uri = flask.url_for('oauth2callback', _external=True)

authorization_response = flask.request.url
flow.fetch_token(authorization_response=authorization_response)

# Store the credentials in the session.
# ACTION ITEM for developers:
#     Store user's access and refresh tokens in your data store if
#     incorporating this code into your real app.
credentials = flow.credentials
flask.session['credentials'] = {
    'token': credentials.token,
    'refresh_token': credentials.refresh_token,
    'token_uri': credentials.token_uri,
    'client_id': credentials.client_id,
    'client_secret': credentials.client_secret,
    'scopes': credentials.scopes}

Ruby

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

  target_url = Google::Auth::WebUserAuthorizer.handle_auth_callback_deferred(request)
  redirect target_url

Node.js

כדי להחליף קוד הרשאה באסימון גישה, צריך להשתמש בשיטה getToken:

const url = require('url');

// Receive the callback from Google's OAuth 2.0 server.
if (req.url.startsWith('/oauth2callback')) {
  // Handle the OAuth 2.0 server response
  let q = url.parse(req.url, true).query;

  // Get access and refresh tokens (if access_type is offline)
  let { tokens } = await oauth2Client.getToken(q.code);
  oauth2Client.setCredentials(tokens);
}

HTTP/REST

כדי להחליף קוד הרשאה באסימון גישה, צריך לבצע קריאה לנקודת הקצה https://oauth2.googleapis.com/token ולהגדיר את הפרמטרים הבאים:

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

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

POST /token HTTP/1.1
Host: oauth2.googleapis.com
Content-Type: application/x-www-form-urlencoded

code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7&
client_id=your_client_id&
client_secret=your_client_secret&
redirect_uri=https%3A//oauth2.example.com/code&
grant_type=authorization_code

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

התשובה כוללת את השדות הבאים:

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

קטע הקוד הבא מציג תגובה לדוגמה:

{
  "access_token": "1/fFAGRNJru1FTz70BzhT3Zg",
  "expires_in": 3920,
  "token_type": "Bearer",
  "scope": "https://www.googleapis.com/auth/drive.metadata.readonly",
  "refresh_token": "1//xEoDL4iW3cxlI7yDbSRFYNG01kVKM2C-259HOF2aQbI"
}

שגיאות

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

invalid_grant

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

קריאה ל-Google APIs

PHP‏

משתמשים באסימון הגישה כדי להפעיל את Google APIs. לשם כך, פועלים לפי השלבים הבאים:

  1. אם צריך להחיל אסימון גישה על אובייקט Google\Client חדש – לדוגמה אם אחסנתם את אסימון הגישה בסשן של משתמש – צריך להשתמש בשיטה setAccessToken:
    $client->setAccessToken($access_token);
  2. יוצרים אובייקט שירות ל-API שאליו רוצים להפעיל את הפונקציה. כדי ליצור אובייקט שירות, מספקים אובייקט Google\Client מורשה לבנאי של ה-API שאליו רוצים להפעיל. לדוגמה, כדי להפעיל את Drive API:
    $drive = new Google\Service\Drive($client);
  3. שולחים בקשות לשירות ה-API באמצעות הממשק שסופק על ידי אובייקט השירות. לדוגמה, כדי להציג את הקבצים ב-Google Drive של המשתמש המאומת:
    $files = $drive->files->listFiles(array())->getItems();

Python

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

  1. יוצרים אובייקט שירות ל-API שאליו רוצים להפעיל את הפונקציה. כדי ליצור אובייקט שירות, מפעילים את השיטה build של ספריית googleapiclient.discovery עם השם והגרסה של ה-API ופרטי הכניסה של המשתמש: לדוגמה, כדי להפעיל את גרסה 3 של Drive API:
    from googleapiclient.discovery import build
    
    drive = build('drive', 'v2', credentials=credentials)
  2. שולחים בקשות לשירות ה-API באמצעות הממשק שסופק על ידי אובייקט השירות. לדוגמה, כדי להציג את הקבצים ב-Google Drive של המשתמש המאומת:
    files = drive.files().list().execute()

Ruby

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

  1. יוצרים אובייקט שירות ל-API שאליו רוצים להפעיל את הפונקציה. לדוגמה, כדי להפעיל את גרסה 3 של Drive API:
    drive = Google::Apis::DriveV3::DriveService.new
  2. מגדירים את פרטי הכניסה בשירות:
    drive.authorization = credentials
  3. שולחים בקשות לשירות ה-API באמצעות הממשק שמסופק על ידי אובייקט השירות. לדוגמה, כדי להציג את הקבצים ב-Google Drive של המשתמש המאומת:
    files = drive.list_files

לחלופין, אפשר לתת הרשאה על בסיס כל שיטה בנפרד על ידי ציון הפרמטר options כשיטה:

files = drive.list_files(options: { authorization: credentials })

Node.js

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

const { google } = require('googleapis');

// Example of using Google Drive API to list filenames in user's Drive.
const drive = google.drive('v3');
drive.files.list({
  auth: oauth2Client,
  pageSize: 10,
  fields: 'nextPageToken, files(id, name)',
}, (err1, res1) => {
  if (err1) return console.log('The API returned an error: ' + err1);
  const files = res1.data.files;
  if (files.length) {
    console.log('Files:');
    files.map((file) => {
      console.log(`${file.name} (${file.id})`);
    });
  } else {
    console.log('No files found.');
  }
});

HTTP/REST

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

אתם יכולים לנסות את כל ממשקי Google API ולראות את ההיקף שלהם במגרש המשחקים של OAuth 2.0.

דוגמאות ל-HTTP GET

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

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

דוגמה מלאה

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

PHP‏

כדי להריץ את הדוגמה הזו:

  1. בשדה API Console, מוסיפים את כתובת ה-URL של המחשב המקומי לרשימת כתובות ה-URL להפניה אוטומטית. לדוגמה, מוסיפים את http://localhost:8080.
  2. יוצרים ספרייה חדשה ומשנים אותה. לדוגמה:
    mkdir ~/php-oauth2-example
    cd ~/php-oauth2-example
  3. מתקינים את ספריית הלקוח של Google API עבור PHP באמצעות Composer:
    composer require google/apiclient:^2.10
  4. יצירת הקבצים index.php ו-oauth2callback.php עם התוכן למטה.
  5. מריצים את הדוגמה עם שרת אינטרנט שמוגדר לשרת PHP. אם אתם משתמשים ב-PHP 5.6 ואילך, תוכלו להשתמש בשרת האינטרנט לבדיקה המובנה של PHP:
    php -S localhost:8080 ~/php-oauth2-example

index.php

<?php
require_once __DIR__.'/vendor/autoload.php';

session_start();

$client = new Google\Client();
$client->setAuthConfig('client_secrets.json');
$client->addScope(Google\Service\Drive::DRIVE_METADATA_READONLY);

if (isset($_SESSION['access_token']) && $_SESSION['access_token']) {
  $client->setAccessToken($_SESSION['access_token']);
  $drive = new Google\Service\Drive($client);
  $files = $drive->files->listFiles(array())->getItems();
  echo json_encode($files);
} else {
  $redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback.php';
  header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}

oauth2callback.php

<?php
require_once __DIR__.'/vendor/autoload.php';

session_start();

$client = new Google\Client();
$client->setAuthConfigFile('client_secrets.json');
$client->setRedirectUri('http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback.php');
$client->addScope(Google\Service\Drive::DRIVE_METADATA_READONLY);

if (! isset($_GET['code'])) {
  $auth_url = $client->createAuthUrl();
  header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));
} else {
  $client->authenticate($_GET['code']);
  $_SESSION['access_token'] = $client->getAccessToken();
  $redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . '/';
  header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}

Python

בדוגמה הזו השתמשנו במסגרת Flask. היא מריצה אפליקציית אינטרנט ב-http://localhost:8080 שמאפשרת לבדוק את תהליך OAuth 2.0. אם עוברים לכתובת ה-URL הזו, אמורים לראות ארבעה קישורים:

  • בדיקה של בקשת API: הקישור הזה מפנה לדף שמנסה לבצע בקשת API לדוגמה. במקרה הצורך, היא תתחיל את תהליך ההרשאה. אם הפעולה בוצעה ללא שגיאות, הדף יציג את תגובת ה-API.
  • בדיקה ישירה של תהליך האימות: הקישור הזה מפנה לדף שמנסה לשלוח את המשתמש דרך תהליך ההרשאה. האפליקציה מבקשת הרשאה לשלוח בקשות API מורשות בשם המשתמש.
  • ביטול פרטי הכניסה הנוכחיים: הקישור מפנה לדף ש מבטל הרשאות שהמשתמש כבר העניק לאפליקציה.
  • ניקוי פרטי הכניסה לסשן Flask: הקישור הזה מסיר את פרטי הכניסה להרשאה שמאוחסנים בסשן של Flask. כך אפשר לראות מה יקרה אם משתמש שכבר העניק הרשאה לאפליקציה שלך ינסה לבצע בקשת API בסשן חדש. הוא גם מאפשר לראות את תגובת ה-API שהאפליקציה שלך תקבל אם משתמש היה מבטל את ההרשאות שהוענקו לאפליקציה שלך, והאפליקציה עדיין ניסתה לאשר בקשה עם אסימון גישה שבוטל.
# -*- coding: utf-8 -*-

import os
import flask
import requests

import google.oauth2.credentials
import google_auth_oauthlib.flow
import googleapiclient.discovery

# This variable specifies the name of a file that contains the OAuth 2.0
# information for this application, including its client_id and client_secret.
CLIENT_SECRETS_FILE = "client_secret.json"

# This OAuth 2.0 access scope allows for full read/write access to the
# authenticated user's account and requires requests to use an SSL connection.
SCOPES = ['https://www.googleapis.com/auth/drive.metadata.readonly']
API_SERVICE_NAME = 'drive'
API_VERSION = 'v2'

app = flask.Flask(__name__)
# Note: A secret key is included in the sample so that it works.
# If you use this code in your application, replace this with a truly secret
# key. See https://flask.palletsprojects.com/quickstart/#sessions.
app.secret_key = 'REPLACE ME - this value is here as a placeholder.'


@app.route('/')
def index():
  return print_index_table()


@app.route('/test')
def test_api_request():
  if 'credentials' not in flask.session:
    return flask.redirect('authorize')

  # Load credentials from the session.
  credentials = google.oauth2.credentials.Credentials(
      **flask.session['credentials'])

  drive = googleapiclient.discovery.build(
      API_SERVICE_NAME, API_VERSION, credentials=credentials)

  files = drive.files().list().execute()

  # Save credentials back to session in case access token was refreshed.
  # ACTION ITEM: In a production app, you likely want to save these
  #              credentials in a persistent database instead.
  flask.session['credentials'] = credentials_to_dict(credentials)

  return flask.jsonify(**files)


@app.route('/authorize')
def authorize():
  # Create flow instance to manage the OAuth 2.0 Authorization Grant Flow steps.
  flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
      CLIENT_SECRETS_FILE, scopes=SCOPES)

  # The URI created here must exactly match one of the authorized redirect URIs
  # for the OAuth 2.0 client, which you configured in the API Console. If this
  # value doesn't match an authorized URI, you will get a 'redirect_uri_mismatch'
  # error.
  flow.redirect_uri = flask.url_for('oauth2callback', _external=True)

  authorization_url, state = flow.authorization_url(
      # Enable offline access so that you can refresh an access token without
      # re-prompting the user for permission. Recommended for web server apps.
      access_type='offline',
      # Enable incremental authorization. Recommended as a best practice.
      include_granted_scopes='true')

  # Store the state so the callback can verify the auth server response.
  flask.session['state'] = state

  return flask.redirect(authorization_url)


@app.route('/oauth2callback')
def oauth2callback():
  # Specify the state when creating the flow in the callback so that it can
  # verified in the authorization server response.
  state = flask.session['state']

  flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
      CLIENT_SECRETS_FILE, scopes=SCOPES, state=state)
  flow.redirect_uri = flask.url_for('oauth2callback', _external=True)

  # Use the authorization server's response to fetch the OAuth 2.0 tokens.
  authorization_response = flask.request.url
  flow.fetch_token(authorization_response=authorization_response)

  # Store credentials in the session.
  # ACTION ITEM: In a production app, you likely want to save these
  #              credentials in a persistent database instead.
  credentials = flow.credentials
  flask.session['credentials'] = credentials_to_dict(credentials)

  return flask.redirect(flask.url_for('test_api_request'))


@app.route('/revoke')
def revoke():
  if 'credentials' not in flask.session:
    return ('You need to <a href="/authorize">authorize</a> before ' +
            'testing the code to revoke credentials.')

  credentials = google.oauth2.credentials.Credentials(
    **flask.session['credentials'])

  revoke = requests.post('https://oauth2.googleapis.com/revoke',
      params={'token': credentials.token},
      headers = {'content-type': 'application/x-www-form-urlencoded'})

  status_code = getattr(revoke, 'status_code')
  if status_code == 200:
    return('Credentials successfully revoked.' + print_index_table())
  else:
    return('An error occurred.' + print_index_table())


@app.route('/clear')
def clear_credentials():
  if 'credentials' in flask.session:
    del flask.session['credentials']
  return ('Credentials have been cleared.<br><br>' +
          print_index_table())


def credentials_to_dict(credentials):
  return {'token': credentials.token,
          'refresh_token': credentials.refresh_token,
          'token_uri': credentials.token_uri,
          'client_id': credentials.client_id,
          'client_secret': credentials.client_secret,
          'scopes': credentials.scopes}

def print_index_table():
  return ('<table>' +
          '<tr><td><a href="/test">Test an API request</a></td>' +
          '<td>Submit an API request and see a formatted JSON response. ' +
          '    Go through the authorization flow if there are no stored ' +
          '    credentials for the user.</td></tr>' +
          '<tr><td><a href="/authorize">Test the auth flow directly</a></td>' +
          '<td>Go directly to the authorization flow. If there are stored ' +
          '    credentials, you still might not be prompted to reauthorize ' +
          '    the application.</td></tr>' +
          '<tr><td><a href="/revoke">Revoke current credentials</a></td>' +
          '<td>Revoke the access token associated with the current user ' +
          '    session. After revoking credentials, if you go to the test ' +
          '    page, you should see an <code>invalid_grant</code> error.' +
          '</td></tr>' +
          '<tr><td><a href="/clear">Clear Flask session credentials</a></td>' +
          '<td>Clear the access token currently stored in the user session. ' +
          '    After clearing the token, if you <a href="/test">test the ' +
          '    API request</a> again, you should go back to the auth flow.' +
          '</td></tr></table>')


if __name__ == '__main__':
  # When running locally, disable OAuthlib's HTTPs verification.
  # ACTION ITEM for developers:
  #     When running in production *do not* leave this option enabled.
  os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1'

  # Specify a hostname and port that are set as a valid redirect URI
  # for your API project in the Google API Console.
  app.run('localhost', 8080, debug=True)

Ruby

בדוגמה הזו נשתמש במסגרת Sinatra.

require 'google/apis/drive_v3'
require 'sinatra'
require 'googleauth'
require 'googleauth/stores/redis_token_store'

configure do
  enable :sessions

  set :client_id, Google::Auth::ClientId.from_file('/path/to/client_secret.json')
  set :scope, Google::Apis::DriveV3::AUTH_DRIVE_METADATA_READONLY
  set :token_store, Google::Auth::Stores::RedisTokenStore.new(redis: Redis.new)
  set :authorizer, Google::Auth::WebUserAuthorizer.new(settings.client_id, settings.scope, settings.token_store, '/oauth2callback')
end

get '/' do
  user_id = settings.client_id.id
  credentials = settings.authorizer.get_credentials(user_id, request)
  if credentials.nil?
    redirect settings.authorizer.get_authorization_url(login_hint: user_id, request: request)
  end
  drive = Google::Apis::DriveV3::DriveService.new
  files = drive.list_files(options: { authorization: credentials })
  "<pre>#{JSON.pretty_generate(files.to_h)}</pre>"
end

get '/oauth2callback' do
  target_url = Google::Auth::WebUserAuthorizer.handle_auth_callback_deferred(request)
  redirect target_url
end

Node.js

כדי להריץ את הדוגמה הזו:

  1. בשדה API Console, מוסיפים את כתובת ה-URL של המכונה המקומית לרשימת כתובות ה-URL להפניה אוטומטית. לדוגמה, מוסיפים את http://localhost.
  2. חשוב לוודא שבמכשירים מותקנות LTS לצורך תחזוקה, LTS פעיל או גרסה נוכחית של Node.js.
  3. יוצרים ספרייה חדשה ומשנים אותה. לדוגמה:
    mkdir ~/nodejs-oauth2-example
    cd ~/nodejs-oauth2-example
  4. Install the Google API Client Library for Node.js using npm:
    npm install googleapis
  5. יוצרים את הקבצים main.js עם התוכן שלמטה.
  6. מריצים את הדוגמה:
    node .\main.js

ראשי.js

const http = require('http');
const https = require('https');
const url = require('url');
const { google } = require('googleapis');

/**
 * To use OAuth2 authentication, we need access to a CLIENT_ID, CLIENT_SECRET, AND REDIRECT_URI.
 * To get these credentials for your application, visit
 * https://console.cloud.google.com/apis/credentials.
 */
const oauth2Client = new google.auth.OAuth2(
  YOUR_CLIENT_ID,
  YOUR_CLIENT_SECRET,
  YOUR_REDIRECT_URL
);

// Access scopes for read-only Drive activity.
const scopes = [
  'https://www.googleapis.com/auth/drive.metadata.readonly'
];

// Generate a url that asks permissions for the Drive activity scope
const authorizationUrl = oauth2Client.generateAuthUrl({
  // 'online' (default) or 'offline' (gets refresh_token)
  access_type: 'offline',
  /** Pass in the scopes array defined above.
    * Alternatively, if only one scope is needed, you can pass a scope URL as a string */
  scope: scopes,
  // Enable incremental authorization. Recommended as a best practice.
  include_granted_scopes: true
});

/* Global variable that stores user credential in this code example.
 * ACTION ITEM for developers:
 *   Store user's refresh token in your data store if
 *   incorporating this code into your real app.
 *   For more information on handling refresh tokens,
 *   see https://github.com/googleapis/google-api-nodejs-client#handling-refresh-tokens
 */
let userCredential = null;

async function main() {
  const server = http.createServer(async function (req, res) {
    // Example on redirecting user to Google's OAuth 2.0 server.
    if (req.url == '/') {
      res.writeHead(301, { "Location": authorizationUrl });
    }

    // Receive the callback from Google's OAuth 2.0 server.
    if (req.url.startsWith('/oauth2callback')) {
      // Handle the OAuth 2.0 server response
      let q = url.parse(req.url, true).query;

      if (q.error) { // An error response e.g. error=access_denied
        console.log('Error:' + q.error);
      } else { // Get access and refresh tokens (if access_type is offline)
        let { tokens } = await oauth2Client.getToken(q.code);
        oauth2Client.setCredentials(tokens);

        /** Save credential to the global variable in case access token was refreshed.
          * ACTION ITEM: In a production app, you likely want to save the refresh token
          *              in a secure persistent database instead. */
        userCredential = tokens;

        // Example of using Google Drive API to list filenames in user's Drive.
        const drive = google.drive('v3');
        drive.files.list({
          auth: oauth2Client,
          pageSize: 10,
          fields: 'nextPageToken, files(id, name)',
        }, (err1, res1) => {
          if (err1) return console.log('The API returned an error: ' + err1);
          const files = res1.data.files;
          if (files.length) {
            console.log('Files:');
            files.map((file) => {
              console.log(`${file.name} (${file.id})`);
            });
          } else {
            console.log('No files found.');
          }
        });
      }
    }

    // Example on revoking a token
    if (req.url == '/revoke') {
      // Build the string for the POST request
      let postData = "token=" + userCredential.access_token;

      // Options for POST request to Google's OAuth 2.0 server to revoke a token
      let postOptions = {
        host: 'oauth2.googleapis.com',
        port: '443',
        path: '/revoke',
        method: 'POST',
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded',
          'Content-Length': Buffer.byteLength(postData)
        }
      };

      // Set up the request
      const postReq = https.request(postOptions, function (res) {
        res.setEncoding('utf8');
        res.on('data', d => {
          console.log('Response: ' + d);
        });
      });

      postReq.on('error', error => {
        console.log(error)
      });

      // Post the request with data
      postReq.write(postData);
      postReq.end();
    }
    res.end();
  }).listen(80);
}
main().catch(console.error);

HTTP/REST

בדוגמה הזו ל-Python נעשה שימוש ב-framework של Flask ובספרייה Requests כדי להדגים את תהליך השימוש ב-OAuth 2.0 באינטרנט. בתהליך הזה מומלץ להשתמש בספריית הלקוח של Google API ל-Python. (הדוגמה בכרטיסייה Python כן משתמשת בספריית הלקוח).

import json

import flask
import requests


app = flask.Flask(__name__)

CLIENT_ID = '123456789.apps.googleusercontent.com'
CLIENT_SECRET = 'abc123'  # Read from a file or environmental variable in a real app
SCOPE = 'https://www.googleapis.com/auth/drive.metadata.readonly'
REDIRECT_URI = 'http://example.com/oauth2callback'


@app.route('/')
def index():
  if 'credentials' not in flask.session:
    return flask.redirect(flask.url_for('oauth2callback'))
  credentials = json.loads(flask.session['credentials'])
  if credentials['expires_in'] <= 0:
    return flask.redirect(flask.url_for('oauth2callback'))
  else:
    headers = {'Authorization': 'Bearer {}'.format(credentials['access_token'])}
    req_uri = 'https://www.googleapis.com/drive/v2/files'
    r = requests.get(req_uri, headers=headers)
    return r.text


@app.route('/oauth2callback')
def oauth2callback():
  if 'code' not in flask.request.args:
    auth_uri = ('https://accounts.google.com/o/oauth2/v2/auth?response_type=code'
                '&client_id={}&redirect_uri={}&scope={}').format(CLIENT_ID, REDIRECT_URI, SCOPE)
    return flask.redirect(auth_uri)
  else:
    auth_code = flask.request.args.get('code')
    data = {'code': auth_code,
            'client_id': CLIENT_ID,
            'client_secret': CLIENT_SECRET,
            'redirect_uri': REDIRECT_URI,
            'grant_type': 'authorization_code'}
    r = requests.post('https://oauth2.googleapis.com/token', data=data)
    flask.session['credentials'] = r.text
    return flask.redirect(flask.url_for('index'))


if __name__ == '__main__':
  import uuid
  app.secret_key = str(uuid.uuid4())
  app.debug = False
  app.run()

כללי אימות של כתובת אתר להפניה מחדש

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

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

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

מארח

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

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

    מזהי URI של הפניות אוטומטיות לא יכולים להכיל את רכיב המשנה של פרטי המשתמש.

    נתיב

    מזהי URI של הפניות אוטומטיות לא יכולים להכיל מעבר נתיב (נקרא גם מעקב לאחור בספרייה), שמיוצג על ידי “/..” או “\..” או על ידי קידוד כתובת ה-URL שלהם.

    שאילתה

    מזהי URI של הפניות אוטומטיות לא יכולים להכיל הפניות אוטומטיות פתוחות.

    מקטע

    מזהי URI של הפניות אוטומטיות לא יכולים להכיל את רכיב המקטע.

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

    הרשאה מצטברת

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

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

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

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

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

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

    דוגמאות הקוד הספציפי לשפה מפורטות בשלב 1: הגדרת הפרמטרים של ההרשאות, ובדוגמאות של כתובת ה-URL להפניה אוטומטית מסוג HTTP/REST בשלב 2: הפניה לשרת OAuth 2.0 של Google – כולן משתמשות בהרשאה מצטברת. דוגמאות הקוד שבהמשך מציגות גם את הקוד שעליך להוסיף כדי להשתמש בהרשאה מצטברת.

    PHP‏

    $client->setIncludeGrantedScopes(true);

    Python

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

    authorization_url, state = flow.authorization_url(
        # Enable offline access so that you can refresh an access token without
        # re-prompting the user for permission. Recommended for web server apps.
        access_type='offline',
        # Enable incremental authorization. Recommended as a best practice.
        include_granted_scopes='true')

    Ruby

    auth_client.update!(
      :additional_parameters => {"include_granted_scopes" => "true"}
    )

    Node.js

    const authorizationUrl = oauth2Client.generateAuthUrl({
      // 'online' (default) or 'offline' (gets refresh_token)
      access_type: 'offline',
      /** Pass in the scopes array defined above.
        * Alternatively, if only one scope is needed, you can pass a scope URL as a string */
      scope: scopes,
      // Enable incremental authorization. Recommended as a best practice.
      include_granted_scopes: true
    });
    

    HTTP/REST

    GET https://accounts.google.com/o/oauth2/v2/auth?
      client_id=your_client_id&
      response_type=code&
      state=state_parameter_passthrough_value&
      scope=https%3A//www.googleapis.com/auth/drive.file&
      redirect_uri=https%3A//oauth2.example.com/code&
      prompt=consent&
      include_granted_scopes=true

    רענון אסימון גישה (גישה אופליין)

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

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

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

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

    PHP‏

    אם לאפליקציה נדרשת גישה אופליין ל-Google API, צריך להגדיר את סוג הגישה של לקוח ה-API כ-offline:

    $client->setAccessType("offline");

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

    Python

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

    authorization_url, state = flow.authorization_url(
        # Enable offline access so that you can refresh an access token without
        # re-prompting the user for permission. Recommended for web server apps.
        access_type='offline',
        # Enable incremental authorization. Recommended as a best practice.
        include_granted_scopes='true')

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

    Ruby

    אם לאפליקציה נדרשת גישה אופליין ל-Google API, צריך להגדיר את סוג הגישה של לקוח ה-API כ-offline:

    auth_client.update!(
      :additional_parameters => {"access_type" => "offline"}
    )

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

    Node.js

    אם לאפליקציה נדרשת גישה אופליין ל-Google API, צריך להגדיר את סוג הגישה של לקוח ה-API כ-offline:

    const authorizationUrl = oauth2Client.generateAuthUrl({
      // 'online' (default) or 'offline' (gets refresh_token)
      access_type: 'offline',
      /** Pass in the scopes array defined above.
        * Alternatively, if only one scope is needed, you can pass a scope URL as a string */
      scope: scopes,
      // Enable incremental authorization. Recommended as a best practice.
      include_granted_scopes: true
    });
    

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

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

    oauth2Client.on('tokens', (tokens) => {
      if (tokens.refresh_token) {
        // store the refresh_token in your secure persistent database
        console.log(tokens.refresh_token);
      }
      console.log(tokens.access_token);
    });

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

    כדי להגדיר refresh_token מאוחר יותר, אפשר להשתמש בשיטה setCredentials:

    oauth2Client.setCredentials({
      refresh_token: `STORED_REFRESH_TOKEN`
    });
    

    אחרי שהלקוח יקבל אסימון רענון, אסימוני הגישה יושלמו וירעננו באופן אוטומטי בקריאה הבאה ל-API.

    HTTP/REST

    כדי לרענן אסימון גישה, האפליקציה שולחת לשרת ההרשאות של Google (https://oauth2.googleapis.com/token) בקשת POST מסוג HTTPS עם הפרמטרים הבאים:

    שדות
    client_id מזהה הלקוח שהתקבל מ- API Console.
    client_secret סוד הלקוח שהתקבל מ- API Console.
    grant_type כפי כפי שמוגדר במפרט OAuth 2.0, הערך בשדה הזה חייב להיות refresh_token.
    refresh_token אסימון הרענון שהוחזר מהחלפת קודי ההרשאה.

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

    POST /token HTTP/1.1
    Host: oauth2.googleapis.com
    Content-Type: application/x-www-form-urlencoded
    
    client_id=your_client_id&
    client_secret=your_client_secret&
    refresh_token=refresh_token&
    grant_type=refresh_token

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

    {
      "access_token": "1/fFAGRNJru1FTz70BzhT3Zg",
      "expires_in": 3920,
      "scope": "https://www.googleapis.com/auth/drive.metadata.readonly",
      "token_type": "Bearer"
    }

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

    ביטול אסימון

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

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

    PHP‏

    כדי לבטל אסימון באופן פרוגרמטי, צריך לקרוא ל-revokeToken():

    $client->revokeToken();

    Python

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

    requests.post('https://oauth2.googleapis.com/revoke',
        params={'token': credentials.token},
        headers = {'content-type': 'application/x-www-form-urlencoded'})

    Ruby

    כדי לבטל אסימון באופן פרוגרמטי, צריך לשלוח בקשת HTTP לנקודת הקצה oauth2.revoke:

    uri = URI('https://oauth2.googleapis.com/revoke')
    response = Net::HTTP.post_form(uri, 'token' => auth_client.access_token)
    

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

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

    Node.js

    כדי לבטל אסימון באופן פרוגרמטי, צריך לשלוח בקשת HTTPS POST לנקודת הקצה של /revoke:

    const https = require('https');
    
    // Build the string for the POST request
    let postData = "token=" + userCredential.access_token;
    
    // Options for POST request to Google's OAuth 2.0 server to revoke a token
    let postOptions = {
      host: 'oauth2.googleapis.com',
      port: '443',
      path: '/revoke',
      method: 'POST',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
        'Content-Length': Buffer.byteLength(postData)
      }
    };
    
    // Set up the request
    const postReq = https.request(postOptions, function (res) {
      res.setEncoding('utf8');
      res.on('data', d => {
        console.log('Response: ' + d);
      });
    });
    
    postReq.on('error', error => {
      console.log(error)
    });
    
    // Post the request with data
    postReq.write(postData);
    postReq.end();
    

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

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

    HTTP/REST

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