שימוש ב-OAuth 2.0 ל'שרתים לשרת'

עליך לשנות את

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

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

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

במסמך זה מוסבר איך אפליקציה יכולה להשלים את תהליך ה-OAuth 2.0 של השרת לשרת באמצעות ספריית הלקוח של Google APIs (מומלץ) או HTTP.

סקירה כללית

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

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

לבסוף, האפליקציה שלכם יכולה להשתמש באסימון הגישה כדי לקרוא ל-Google APIs.

יצירת חשבון שירות

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

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

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

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

ראשית, צור חשבון שירות:

  1. פתח את ה- Service accounts page.
  2. If prompted, select a project, or create a new one.
  3. לחץ על צור חשבון שירות .
  4. תחת פרטי חשבון שירות , הקלד שם, מזהה ותיאור עבור חשבון השירות ולאחר מכן לחץ על צור והמשך .
  5. אופציונלי: תחת הענק גישה לחשבון שירות זה לפרויקט , בחר את תפקידי IAM להעניק לחשבון השירות.
  6. לחץ על המשך .
  7. אופציונלי: תחת הענק למשתמשים גישה לחשבון שירות זה , הוסף את המשתמשים או הקבוצות המורשים להשתמש ולנהל את חשבון השירות.
  8. לחץ על סיום .

לאחר מכן, צור מפתח חשבון שירות:

  1. לחץ על כתובת הדוא"ל של חשבון השירות שיצרת.
  2. לחץ על הכרטיסייה מפתחות .
  3. ברשימה הנפתחת הוסף מפתח , בחר צור מפתח חדש .
  4. לחץ על צור .

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

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

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

האצלת סמכויות ברמת הדומיין לחשבון השירות

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

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

  1. מ מסוף Admin של הדומיין שלך ב-Google Workspace, נכנסים לתפריט הראשי > אבטחה > בקרת גישה ונתונים > אמצעי בקרה ל-API.
  2. בחלונית הענקת גישה ברמת הדומיין, בוחרים באפשרות ניהול האצלה של כל הדומיין.
  3. לוחצים על הוספת חדש.
  4. בשדה Client ID, מזינים את Client ID של חשבון השירות. מזהה הלקוח של חשבון השירות שלך מופיע ב- Service accounts page.
  5. בשדה היקפי ההרשאות של OAuth (מופרדים בפסיקים), מזינים רשימה של היקפי הרשאות שצריכים להעניק לאפליקציה גישה אליהם. לדוגמה, אם לאפליקציה שלכם נדרשת גישה מלאה ברמת הדומיין ל-Google Drive API ול-Google Calendar API, צריך להזין: https://www.googleapis.com/auth/drive, https://www.googleapis.com/auth/calendar.
  6. לוחצים על Authorize.

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

הכנה לביצוע קריאת API מואצלת

Java

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

import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.services.sqladmin.SQLAdminScopes;

// ...

GoogleCredential credential = GoogleCredential.fromStream(new FileInputStream("MyProject-1234.json"))
    .createScoped(Collections.singleton(SQLAdminScopes.SQLSERVICE_ADMIN));

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

האצלת סמכות ברמת הדומיין

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

GoogleCredential credential = GoogleCredential.fromStream(new FileInputStream("MyProject-1234.json"))
    .createScoped(Collections.singleton(SQLAdminScopes.SQLSERVICE_ADMIN))
    .createDelegated("workspace-user@example.com");

הקוד שלמעלה משתמש באובייקט GoogleCredential כדי להפעיל את method createDelegated(). הארגומנט של השיטה createDelegated() חייב להיות משתמש ששייך לחשבון Workspace שלך. הקוד שיישלח את הבקשה ישתמש בפרטי הכניסה האלה כדי לקרוא לממשקי Google API באמצעות חשבון השירות שלך.

Python

אחרי שמקבלים את כתובת האימייל של הלקוח ואת המפתח הפרטי מה- API Console, צריך להשתמש בספריית הלקוח של Google APIs ל-Python כדי לבצע את השלבים הבאים:

  1. יצירת אובייקט Credentials מהפרטי כניסה של חשבון השירות, ולהיקפים שלאפליקציה נדרשת גישה אליהם. למשל:
    from google.oauth2 import service_account
    
    SCOPES = ['https://www.googleapis.com/auth/sqlservice.admin']
    SERVICE_ACCOUNT_FILE = '/path/to/service.json'
    
    credentials = service_account.Credentials.from_service_account_file(
            SERVICE_ACCOUNT_FILE, scopes=SCOPES)

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

  2. האצלת סמכות ברמת הדומיין

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

    delegated_credentials = credentials.with_subject('user@example.org')

השתמשו באובייקט Credentials כדי לקרוא ל-Google APIs באפליקציה.

HTTP/REST

אחרי שמקבלים את מספר הלקוח והמפתח הפרטי מה- API Console, האפליקציה צריכה לבצע את השלבים הבאים:

  1. יצירת אסימון אינטרנט מסוג JSON (JWT, הגייה, "jot") הכולל כותרת, קבוצת תלונות וחתימה.
  2. ניתן לבקש אסימון גישה משרת ההרשאות של Google OAuth 2.0.
  3. טפל בתגובת ה-JSON שמחזירה שרת ההרשאות.

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

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

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

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

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

יצירת JWT

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

JWT מורכב כך:

{Base64url encoded header}.{Base64url encoded claim set}.{Base64url encoded signature}

מחרוזת הבסיס של החתימה:

{Base64url encoded header}.{Base64url encoded claim set}
יצירת כותרת JWT

הכותרת מורכבת משלושה שדות שמציינים את אלגוריתם החתימה, פורמט הטענה ו[מזהה המפתח של מפתח חשבון השירות](https://cloud.google.com/iam/docs/reference/rest/v1/projects.serviceAccounts.keys) ששימשו לחתימה על ה-JWT. האלגוריתם והפורמט הם שדות חובה, ולכל שדה יש ערך אחד בלבד. ככל שנוסיף עוד אלגוריתמים ופורמטים, הכותרת הזו תשתנה בהתאם. מזהה המפתח הוא אופציונלי. אם יצוין מזהה מפתח שגוי, המערכת של GCP תנסה לאמת את כל המפתחות המשויכים לחשבון השירות כדי לאמת את האסימון ותדחה את האסימון אם לא יימצא מפתח חוקי. Google שומרת לעצמה את הזכות לדחות אסימונים עם מזהי מפתחות שגויים בעתיד.

חשבונות שירות מסתמכים על אלגוריתם RSA SHA-256 ועל פורמט אסימון JWT. כתוצאה מכך, הייצוג של כותרת ה-JSON הוא:

{"alg":"RS256","typ":"JWT", "kid":"370ab79b4513eb9bad7c9bd16a95cb76b5b2a56a"}

הייצוג של Base64url הוא:

          eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsICJraWQiOiIzNzBhYjc5YjQ1MTNlYjliYWQ3YzliZDE2YTk1Y2I3NmI1YjJhNTZhIn0=
יצירת תלונה על JWT

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

תלונות נדרשות

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

שם תיאור
iss כתובת האימייל של חשבון השירות.
scope רשימה מופרדת ברווחים של ההרשאות שהאפליקציה מבקשת.
aud מתאר את היעד של הטענה. כששולחים אסימון גישה, הערך הזה הוא תמיד https://oauth2.googleapis.com/token.
exp מועד התפוגה של הקביעה, שצוין בשניות מאז 00:00:00 UTC, 1 בינואר 1970. הערך הזה מוגדר לשעה אחת לכל היותר לאחר תאריך ההנפקה.
iat מועד הנפקת התלונה, שצוינו בשניות מאז 00:00:00 UTC, 1 בינואר 1970.

ייצוג JSON של שדות החובה בקבוצת הצהרות JWT מוצג למטה:

{
  "iss": "761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer.gserviceaccount.com",
  "scope": "https://www.googleapis.com/auth/devstorage.read_only",
  "aud": "https://oauth2.googleapis.com/token",
  "exp": 1328554385,
  "iat": 1328550785
}
תלונות נוספות

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

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

שם תיאור
sub כתובת האימייל של המשתמש שהאפליקציה מבקשת גישה אליו.

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

דוגמה לקבוצת תלונות של JWT שכוללת את השדה sub מוצגת בהמשך:

{
  "iss": "761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer.gserviceaccount.com",
  "sub": "some.user@example.com",
  "scope": "https://www.googleapis.com/auth/prediction",
  "aud": "https://oauth2.googleapis.com/token",
  "exp": 1328554385,
  "iat": 1328550785
}
קידוד קבוצת התלונות של JWT

בדומה לכותרת JWT, יש להגדיר את קבוצת התלונות של JWT טורית לקידוד UTF-8 וקידוד Base64url-safe. דוגמה לייצוג JSON של תלונה על הפרת זכויות יוצרים שנשלחת מ-JWT:

{
  "iss": "761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer.gserviceaccount.com",
  "scope": "https://www.googleapis.com/auth/prediction",
  "aud": "https://oauth2.googleapis.com/token",
  "exp": 1328554385,
  "iat": 1328550785
}
מחשב את החתימה

JSON Web Signature (JWS) הוא המפרט שמנחה את המכניקה של יצירת החתימה ב-JWT. הקלט לחתימה הוא מערך הבייטים של התוכן הבא:

{Base64url encoded header}.{Base64url encoded claim set}

חובה להשתמש באלגוריתם החתימה בכותרת JWT בעת חישוב החתימה. אלגוריתם החתימה היחיד שנתמך על ידי שרת ההרשאות של Google OAuth 2.0 הוא RSA באמצעות אלגוריתם הגיבוב SHA-256. הערך הזה מופיע כ-RS256 בשדה alg בכותרת JWT.

חותמים על ייצוג UTF-8 של הקלט באמצעות SHA256withRSA (נקרא גם RSASSA-PKCS1-V1_5-SIGN באמצעות פונקציית הגיבוב SHA-256) באמצעות המפתח הפרטי שמתקבל מ- Google API Console. הפלט יהיה מערך בבייט.

לאחר מכן, החתימה חייבת להיות בקידוד Base64url. הכותרת, הצהרת הבעלות והחתימה מקובצות יחד עם תו נקודה (.). התוצאה היא ה-JWT. היא אמורה להיות ברורה (מעברי שורה שנוספו כדי להבהיר):

{Base64url encoded header}.
{Base64url encoded claim set}.
{Base64url encoded signature}

זוהי דוגמה של JWT לפני קידוד Base64url:

{"alg":"RS256","typ":"JWT"}.
{
"iss":"761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer.gserviceaccount.com",
"scope":"https://www.googleapis.com/auth/prediction",
"aud":"https://oauth2.googleapis.com/token",
"exp":1328554385,
"iat":1328550785
}.
[signature bytes]

זוהי דוגמה ל-JWT שנחתם ומוכן להעברה:

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI3NjEzMjY3OTgwNjktcjVtbGpsbG4xcmQ0bHJiaGc3NWVmZ2lncDM2bTc4ajVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzY29wZSI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2F1dGgvcHJlZGljdGlvbiIsImF1ZCI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL29hdXRoMi92NC90b2tlbiIsImV4cCI6MTMyODU1NDM4NSwiaWF0IjoxMzI4NTUwNzg1fQ.UFUt59SUM2_AW4cRU8Y0BYVQsNTo4n7AFsNrqOpYiICDu37vVt-tw38UKzjmUKtcRsLLjrR3gFW3dNDMx_pL9DVjgVHDdYirtrCekUHOYoa1CMR66nxep5q5cBQ4y4u2kIgSvChCTc9pmLLNoIem-ruCecAJYgI9Ks7pTnW1gkOKs0x3YpiLpzplVHAkkHztaXiJdtpBcY1OXyo6jTQCa3Lk2Q3va1dPkh_d--GU2M5flgd8xNBPYw4vxyt0mP59XZlHMpztZt0soSgObf7G3GXArreF_6tpbFsS3z2t5zkEiHuWJXpzcYr5zWTRPDEHsejeBSG8EgpLDce2380ROQ

שליחת הבקשה לאסימון הגישה

לאחר יצירת JWT חתום, אפליקציה יכולה להשתמש בו כדי לבקש אסימון גישה. בקשת אסימון הגישה היא בקשת POST מסוג HTTPS, והגוף מקודד ככתובת URL. כתובת ה-URL מוצגת למטה:

https://oauth2.googleapis.com/token

בקשת HTTPS של POST מחייבת את הפרמטרים הבאים:

שם תיאור
grant_type יש להשתמש במחרוזת הבאה, בקידוד כתובת ה-URL לפי הצורך: urn:ietf:params:oauth:grant-type:jwt-bearer
assertion ה-JWT, כולל חתימה.

בהמשך מוצגת קובץ Dump של בקשת ה-HTTPS POST שמשמשת בבקשת אסימון גישה:

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

grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI3NjEzMjY3OTgwNjktcjVtbGpsbG4xcmQ0bHJiaGc3NWVmZ2lncDM2bTc4ajVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzY29wZSI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2F1dGgvcHJlZGljdGlvbiIsImF1ZCI6Imh0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbS9vL29hdXRoMi90b2tlbiIsImV4cCI6MTMyODU3MzM4MSwiaWF0IjoxMzI4NTY5NzgxfQ.ixOUGehweEVX_UKXv5BbbwVEdcz6AYS-6uQV6fGorGKrHf3LIJnyREw9evE-gs2bmMaQI5_UbabvI4k-mQE4kBqtmSpTzxYBL1TCd7Kv5nTZoUC1CmwmWCFqT9RE6D7XSgPUh_jF1qskLa2w0rxMSjwruNKbysgRNctZPln7cqQ

לפניכם אותה בקשה, באמצעות curl:

curl -d 'grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI3NjEzMjY3OTgwNjktcjVtbGpsbG4xcmQ0bHJiaGc3NWVmZ2lncDM2bTc4ajVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzY29wZSI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2F1dGgvcHJlZGljdGlvbiIsImF1ZCI6Imh0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbS9vL29hdXRoMi90b2tlbiIsImV4cCI6MTMyODU3MzM4MSwiaWF0IjoxMzI4NTY5NzgxfQ.RZVpzWygMLuL-n3GwjW1_yhQhrqDacyvaXkuf8HcJl8EtXYjGjMaW5oiM5cgAaIorrqgYlp4DPF_GuncFqg9uDZrx7pMmCZ_yHfxhSCXru3gbXrZvAIicNQZMFxrEEn4REVuq7DjkTMyCMGCY1dpMa8aWfTQFt3Eh7smLchaZsU
' https://oauth2.googleapis.com/token

טיפול בתגובה

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

{
  "access_token": "1/8xbJqaOZXSUZbHLl5EOtu1pxz3fmmetKx9W8CV4t79M",
  "scope": "https://www.googleapis.com/auth/prediction"
  "token_type": "Bearer",
  "expires_in": 3600
}

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

קריאה ל-Google APIs

Java

כדי להתקשר ל-Google APIs באמצעות אובייקט GoogleCredential, פועלים לפי השלבים הבאים:

  1. ניתן ליצור אובייקט שירות עבור ה-API שאליו רוצים להתקשר באמצעות האובייקט GoogleCredential. למשל:
    SQLAdmin sqladmin =
        new SQLAdmin.Builder(httpTransport, JSON_FACTORY, credential).build();
  2. צריך לשלוח בקשות לשירות ה-API באמצעות הממשק שסופק על ידי האובייקט בשירות. לדוגמה, כדי ליצור רשימה של המופעים של מסדי נתונים ב-Cloud SQL בפרויקט מרתק לדוגמה-123:
    SQLAdmin.Instances.List instances =
        sqladmin.instances().list("exciting-example-123").execute();

Python

כדי להתקשר ל-Google APIs באמצעות האובייקט Credentials המורשה, פועלים לפי השלבים הבאים:

  1. עליך לבנות אובייקט שירות עבור ה-API שאליו ברצונך להתקשר. כדי ליצור אובייקט שירות, צריך לקרוא לפונקציה build עם השם והגרסה של ה-API והאובייקט Credentials המורשה. לדוגמה, כדי לקרוא לגרסה 1beta3 של Cloud SQL Administration API:
    import googleapiclient.discovery
    
    sqladmin = googleapiclient.discovery.build('sqladmin', 'v1beta3', credentials=credentials)
  2. צריך לשלוח בקשות לשירות ה-API באמצעות הממשק שסופק על ידי האובייקט בשירות. לדוגמה, כדי ליצור רשימה של המופעים של מסדי נתונים ב-Cloud SQL בפרויקט מרתק לדוגמה-123:
    response = sqladmin.instances().list(project='exciting-example-123').execute()

HTTP/REST

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

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

דוגמאות ל-HTTP GET

קריאה לנקודת הקצה drive.files של Drive Drive 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

כשתוקף אסימוני הגישה פג

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

קודי שגיאה של JWT

שדה error שדה error_description משמעות איך פותרים את הבעיה
unauthorized_client Unauthorized client or scope in request. אם ניסית להשתמש בהענקת גישה ברמת הדומיין, חשבון השירות לא מורשה במסוף Admin של הדומיין של המשתמש.

צריך לוודא שחשבון השירות מורשה בדף הענקת גישה ברמת הדומיין במסוף Admin, עבור המשתמש בתלונה sub (בשדה).

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

unauthorized_client Client is unauthorized to retrieve access tokens using this method, or client not authorized for any of the scopes requested. חשבון השירות אושר באמצעות כתובת האימייל של הלקוח ולא באמצעות מספר הלקוח (מספר) במסוף Admin. בדף הענקת גישה ברמת הדומיין במסוף Admin, מסירים את הלקוח ומוסיפים אותו מחדש באמצעות המזהה המספרי.
access_denied (כל ערך) אם בחרת להקצות גישה ברמת הדומיין, אחת או יותר מהיקפי ההרשאות המבוקשים לא מורשית במסוף Admin.

חשוב לוודא שחשבון השירות מורשה בדף הענקת גישה ברמת הדומיין במסוף Admin, עבור המשתמש בתלונה sub (שדה) ושהוא כולל את כל ההיקפים שביקשת בתלונה של scope ב-JWT.

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

admin_policy_enforced (כל ערך) חשבון Google לא יכול להעניק הרשאה להיקף אחד או יותר המבוקשים, בהתאם למדיניות של האדמין ב-Google Workspace.

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

invalid_client (כל ערך)

לקוח OAuth או אסימון JWT אינם תקינים או מוגדרים באופן שגוי.

לפרטים נוספים, קראו את תיאור השגיאה.

חשוב לוודא שהאסימון JWT חוקי ומכיל הצהרות נכונות.

מוודאים שחשבון הלקוח וחשבון ה-OAuth מוגדרים נכון ושכתובת האימייל נכונה.

יש לוודא שהאסימון JWT נכון ושהונפק עבור מספר הלקוח בבקשה.

invalid_grant Not a valid email. המשתמש הזה לא קיים. צריך לבדוק שכתובת האימייל שציינת בתלונה (שדה) ב-sub נכונה.
invalid_grant

Invalid JWT: Token must be a short-lived token (60 minutes) and in a reasonable timeframe. Check your 'iat' and 'exp' values and use a clock with skew to account for clock differences between systems.

בדרך כלל, המשמעות היא שהשעה במערכת המקומית אינה נכונה. יכול להיות גם שערך exp יהיה יותר מ-65 דקות בעתיד מהערך של iat, או שהערך של exp יהיה נמוך מהערך של iat.

ודאו שהשעון במערכת שבה נוצר ה-JWT נכון. אם צריך, מסנכרנים את השעה עם Google NTP.

invalid_grant Invalid JWT Signature.

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

לחלופין, ייתכן שהארגומנט של JWT מקודד באופן שגוי – הוא חייב להיות מקודד ב-Base64, בלי שורות חדשות או מרווח פנימי שווה.

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

כדאי לנסות להשתמש בספריית OAuth ש-Google מספקת כדי לוודא ש-JWT נוצר כראוי.

invalid_scope Invalid OAuth scope or ID token audience provided. לא נשלחו בקשות להיקפים (היקף ריק של היקפים), או שאחד מההיקפים המבוקשים לא קיים (כלומר לא חוקי).

יש לוודא שהתלונה scope (שדה) של ה-JWT מאוכלסת, ולהשוות את ההיקפים שהיא מכילה להיקפים המתועדים של ממשקי ה-API שבהם רוצים להשתמש, כדי לוודא שאין שגיאות או שגיאות הקלדה.

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

disabled_client The OAuth client was disabled. המפתח המשמש לחתימה על הצהרת ה-JWT מושבת.

נכנסים אל Google API Console, ובקטע IAM & Admin > Service Accounts, מפעילים את חשבון השירות שמכיל את "מזהה המפתח" שמשמש לחתימה על ההצהרה.

org_internal This client is restricted to users within its organization. מזהה הלקוח ב-OAuth בבקשה הוא חלק מפרויקט שמגביל את הגישה לחשבונות Google ב ארגון ספציפי ב-Google Cloud.

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

נספח: הרשאה לחשבון שירות ללא OAuth

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

אם ממשק ה-API שאליו רוצים להתקשר פורסם על ידי ממשק שירות במאגר של ממשקי Google API ב-GitHub, אפשר לבצע קריאות ל-API באמצעות JWT במקום אסימון גישה. לשם כך:

  1. יוצרים חשבון שירות כפי שמתואר למעלה. חשוב לשמור את קובץ ה-JSON שמתקבל כשיוצרים את החשבון.
  2. באמצעות כל ספריית JWT רגילה, כמו זו שבכתובת jwt.io, יוצרים JWT עם כותרת ומטען ייעודי (payload) כמו:
    {
      "alg": "RS256",
      "typ": "JWT",
      "kid": "abcdef1234567890"
    }
    .
    {
      "iss": "123456-compute@developer.gserviceaccount.com",
      "sub": "123456-compute@developer.gserviceaccount.com",
      "aud": "https://firestore.googleapis.com/",
      "iat": 1511900000,
      "exp": 1511903600
    }
    • בשדה kid בכותרת, צריך לציין את המזהה של המפתח הפרטי של חשבון השירות שלך. אפשר למצוא את הערך הזה בשדה private_key_id בקובץ ה-JSON של חשבון השירות שלך.
    • בשדות iss ו-sub, מציינים את כתובת האימייל של חשבון השירות. אפשר למצוא את הערך הזה בשדה client_email בקובץ ה-JSON של חשבון השירות שלך.
    • בשדה aud, מציינים את נקודת הקצה ל-API. למשל: https://SERVICE.googleapis.com/
    • בשדה iat, מציינים את השעה הנוכחית ב-Unix, ובשדה exp מציינים את השעה בדיוק 3, 600 שניות, לאחר שה-JWT יפוג.

חותמים את JWT באמצעות RSA-256 באמצעות המפתח הפרטי שנמצא בקובץ ה-JSON של חשבון השירות.

לדוגמה:

Java

באמצעות google-api-java-client ו-java-jwt:

GoogleCredential credential =
        GoogleCredential.fromStream(new FileInputStream("MyProject-1234.json"));
PrivateKey privateKey = credential.getServiceAccountPrivateKey();
String privateKeyId = credential.getServiceAccountPrivateKeyId();

long now = System.currentTimeMillis();

try {
    Algorithm algorithm = Algorithm.RSA256(null, privateKey);
    String signedJwt = JWT.create()
        .withKeyId(privateKeyId)
        .withIssuer("123456-compute@developer.gserviceaccount.com")
        .withSubject("123456-compute@developer.gserviceaccount.com")
        .withAudience("https://firestore.googleapis.com/")
        .withIssuedAt(new Date(now))
        .withExpiresAt(new Date(now + 3600 * 1000L))
        .sign(algorithm);
} catch ...

Python

באמצעות PyJWT:

iat = time.time()
exp = iat + 3600
payload = {'iss': '123456-compute@developer.gserviceaccount.com',
           'sub': '123456-compute@developer.gserviceaccount.com',
           'aud': 'https://firestore.googleapis.com/',
           'iat': iat,
           'exp': exp}
additional_headers = {'kid': PRIVATE_KEY_ID_FROM_JSON}
signed_jwt = jwt.encode(payload, PRIVATE_KEY_FROM_JSON, headers=additional_headers,
                       algorithm='RS256')
  1. יש להפעיל את ה-API ולהשתמש ב-JWT החתום כאסימון הנושא:
    GET /v1/projects/abc/databases/123/indexes HTTP/1.1
    Authorization: Bearer SIGNED_JWT
    Host: firestore.googleapis.com