OpenID Connect

ממשקי ה-API של OAuth 2.0 של Google יכולים לשמש גם לאימות וגם להרשאה. מסמך זה מתאר את הטמעת OAuth 2.0 שלנו לאימות, שתואמת למפרט של OpenID Connect ומאושרת על ידי OpenID. המסמכים בנושא שימוש ב-OAuth 2.0 לגישה אל ממשקי ה-API של Google חלים גם על השירות הזה. כדי לחקור את הפרוטוקול הזה באופן אינטראקטיבי, מומלץ להשתמש ב-Google OAuth 2.0 Playground. כדי לקבל עזרה בנושא Stack Overflow, אפשר לתייג את השאלות ב-'google-oauth'.

הגדרת OAuth 2.0

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

קבלת פרטי כניסה ל-OAuth 2.0

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

To view the client ID and client secret for a given OAuth 2.0 credential, click the following text: Select credential. In the window that opens, choose your project and the credential you want, then click View.

Or, view your client ID and client secret from the Credentials page in API Console:

  1. Go to the Credentials page.
  2. Click the name of your credential or the pencil () icon. Your client ID and secret are at the top of the page.

הגדרת URI להפניה אוטומטית

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

要创建,查看或编辑给定OAuth 2.0凭据的重定向URI,请执行以下操作:

  1. Go to the Credentials page.
  2. 在页面的OAuth 2.0客户端ID部分中,点击一个凭据。
  3. 查看或编辑重定向URI。

如果“凭据”页面上没有OAuth 2.0客户端ID部分,则您的项目没有OAuth凭据。要创建一个,点击创建凭证

התאמה אישית של מסך ההסכמה של המשתמש

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

במסך הסכמת המשתמש מוצגים גם פרטי מיתוג, כמו שם המוצר, הלוגו וכתובת ה-URL של דף הבית. יש לך שליטה על פרטי המיתוג ב API Console.

כדי לאפשר את מסך ההסכמה של הפרויקט שלך:

  1. פתח את Consent Screen page ב- Google API Console .
  2. If prompted, select a project, or create a new one.
  3. מלא את הטופס ולחץ על שמור .

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

צילום מסך של דף הסכמה

גישה לשירות

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

אם בוחרים שלא להשתמש בספרייה, צריך לבצע את ההוראות בשארית המסמך הזה, שמתאר את הזרימה של בקשת ה-HTTP שמתחת לספריות הזמינות.

אימות המשתמש

אימות המשתמש כרוך בקבלת אסימון מזהה ואימות שלו. אסימונים מזהים הם תכונה סטנדרטית של OpenID Connect, שמיועדת לשימוש לצורך שיתוף טענות נכונות (assertions) של זהות באינטרנט.

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

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

זרימה של השרת

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

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

1. יצירת אסימון מצב למניעת זיוף

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

אסימון מצב (state) יכול להיות מחרוזת של 30 תווים בערך שנוצרים באמצעות מחולל מספרים אקראיים באיכות גבוהה. אפשרות אחרת היא גיבוב (hash) שנוצר על ידי חתימה על חלק ממשתני המצב של הסשן באמצעות מפתח שנשמר בסוד בקצה העורפי.

הקוד הבא מדגים איך יוצרים אסימוני סשן ייחודיים.

PHP

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

// Create a state token to prevent request forgery.
// Store it in the session for later validation.
$state = bin2hex(random_bytes(128/8));
$app['session']->set('state', $state);
// Set the client ID, token state, and application name in the HTML while
// serving it.
return $app['twig']->render('index.html', array(
    'CLIENT_ID' => CLIENT_ID,
    'STATE' => $state,
    'APPLICATION_NAME' => APPLICATION_NAME
));

Java

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

// Create a state token to prevent request forgery.
// Store it in the session for later validation.
String state = new BigInteger(130, new SecureRandom()).toString(32);
request.session().attribute("state", state);
// Read index.html into memory, and set the client ID,
// token state, and application name in the HTML before serving it.
return new Scanner(new File("index.html"), "UTF-8")
    .useDelimiter("\\A").next()
    .replaceAll("[{]{2}\\s*CLIENT_ID\\s*[}]{2}", CLIENT_ID)
    .replaceAll("[{]{2}\\s*STATE\\s*[}]{2}", state)
    .replaceAll("[{]{2}\\s*APPLICATION_NAME\\s*[}]{2}",
    APPLICATION_NAME);

Python

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

# Create a state token to prevent request forgery.
# Store it in the session for later validation.
state = hashlib.sha256(os.urandom(1024)).hexdigest()
session['state'] = state
# Set the client ID, token state, and application name in the HTML while
# serving it.
response = make_response(
    render_template('index.html',
                    CLIENT_ID=CLIENT_ID,
                    STATE=state,
                    APPLICATION_NAME=APPLICATION_NAME))

2. איך שולחים בקשת אימות ל-Google

השלב הבא הוא יצירה של בקשת GET מסוג HTTPS עם הפרמטרים המתאימים של ה-URI. שימו לב לשימוש ב-HTTPS במקום ב-HTTP בכל שלבי התהליך. חיבורי HTTP נדחים. צריך לאחזר את ה-URI הבסיסי ממסמך Discovery באמצעות ערך המטא-נתונים authorization_endpoint. בדיון הבא ההנחה היא שה-URI הבסיסי הוא https://accounts.google.com/o/oauth2/v2/auth.

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

  • client_id, שמקבלים מ- API Console Credentials page .
  • response_type, שבבקשת זרימה של קוד הרשאה בסיסי צריך להיות code. (מידע נוסף מופיע בכתובת response_type.)
  • scope, שבבקשה בסיסית צריך להיות openid email. (מידע נוסף זמין בכתובת scope.)
  • redirect_uri צריכה להיות נקודת הקצה מסוג HTTP בשרת שתקבל את התגובה מ-Google. הערך חייב להיות זהה לאחד ממזהי ה-URI המורשים להפניה אוטומטית בלקוח OAuth 2.0 שהגדרת ב API Console Credentials page. אם הערך הזה לא תואם ל-URI מורשה, הבקשה תיכשל ותוצג שגיאת redirect_uri_mismatch.
  • state צריך לכלול את הערך של אסימון הסשן הייחודי נגד זיופים, וגם כל מידע אחר שנדרש כדי לשחזר את ההקשר כשהמשתמש חוזר לאפליקציה, למשל כתובת ה-URL להתחלה. (מידע נוסף זמין בכתובת state.)
  • nonce הוא ערך אקראי שנוצר על ידי האפליקציה שלך, ומאפשר הגנת הפעלה מחדש כשהיא קיימת.
  • login_hint יכול להיות כתובת האימייל של המשתמש, או המחרוזת sub, המקבילה למזהה Google של המשתמש. אם לא מציינים login_hint והמשתמש מחובר כרגע, מסך ההסכמה כולל בקשה לאישור לשחרור כתובת האימייל של המשתמש באפליקציה שלך. (מידע נוסף זמין בכתובת login_hint.)
  • אפשר להשתמש בפרמטר hd כדי לבצע אופטימיזציה של התהליך ב-OpenID Connect למשתמשים בדומיין מסוים שמשויך לארגון ב-Google Workspace או ב-Cloud (מידע נוסף זמין בכתובת hd).

זוהי דוגמה ל-URI מלא לאימות של OpenID Connect, עם מעברי שורה ורווחים לשיפור קריא:

https://accounts.google.com/o/oauth2/v2/auth?
 response_type=code&
 client_id=424911365001.apps.googleusercontent.com&
 scope=openid%20email&
 redirect_uri=https%3A//oauth2.example.com/code&
 state=security_token%3D138r5719ru3e1%26url%3Dhttps%3A%2F%2Foauth2-login-demo.example.com%2FmyHome&
 login_hint=jsmith@example.com&
 nonce=0394852-3190485-2490358&
 hd=example.com

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

3. אישור אסימון מצב למניעת זיוף

התשובה תישלח אל redirect_uri שציינת בבקשה. כל התגובות מוחזרות במחרוזת השאילתה, כמו בדוגמה הבאה:

https://oauth2.example.com/code?state=security_token%3D138r5719ru3e1%26url%3Dhttps%3A%2F%2Foa2cb.example.com%2FmyHome&code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7&scope=openid%20email%20https://www.googleapis.com/auth/userinfo.email

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

הקוד הבא מראה אישור של אסימוני הסשן שיצרתם בשלב 1:

PHP

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

// Ensure that there is no request forgery going on, and that the user
// sending us this connect request is the user that was supposed to.
if ($request->get('state') != ($app['session']->get('state'))) {
  return new Response('Invalid state parameter', 401);
}

Java

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

// Ensure that there is no request forgery going on, and that the user
// sending us this connect request is the user that was supposed to.
if (!request.queryParams("state").equals(
    request.session().attribute("state"))) {
  response.status(401);
  return GSON.toJson("Invalid state parameter.");
}

Python

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

# Ensure that the request is not a forgery and that the user sending
# this connect request is the expected user.
if request.args.get('state', '') != session['state']:
  response = make_response(json.dumps('Invalid state parameter.'), 401)
  response.headers['Content-Type'] = 'application/json'
  return response

4. החלפת code באסימון גישה ובאסימון מזהה

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

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

הבקשה בפועל עשויה להיראות כמו בדוגמה הבאה:

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

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

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

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

5. קבלת פרטי המשתמשים מהאסימון המזהה

אסימון מזהה הוא אובייקט JWT (JSON Web Token), כלומר, אובייקט JSON בקידוד Base64 עם חתימה קריפטוגרפית. בדרך כלל, חשוב לאמת אסימון מזהה לפני שמשתמשים בו, אבל מכיוון שהתקשורת ישירה עם Google דרך ערוץ HTTPS ללא גישור ומשתמשת בסוד הלקוח כדי לאמת את זהותך מול Google, תהיה לך אפשרות להיות בטוחים שהאסימון שקיבלת אכן מגיע מ-Google ושהוא תקין. אם השרת שלך מעביר את האסימון המזהה לרכיבים אחרים של האפליקציה, חשוב מאוד שהרכיבים האחרים יאמתו את האסימון לפני השימוש בו.

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

מטען ייעודי (payload) של אסימון מזהה

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

{
  "iss": "https://accounts.google.com",
  "azp": "1234987819200.apps.googleusercontent.com",
  "aud": "1234987819200.apps.googleusercontent.com",
  "sub": "10769150350006150715113082367",
  "at_hash": "HK6E_P6Dh8Y93mRNtsDB1Q",
  "hd": "example.com",
  "email": "jsmith@example.com",
  "email_verified": "true",
  "iat": 1353601026,
  "exp": 1353604926,
  "nonce": "0394852-3190485-2490358"
}

אסימונים של מזהה Google עשויים להכיל את השדות הבאים (שנקראים הצהרות):

דירוג מסופק תיאור
aud always הקהל שעבורו מיועד האסימון המזהה הזה. הוא חייב להיות אחד ממזהי הלקוח מסוג OAuth 2.0 של האפליקציה שלך.
exp always מועד התפוגה שבו אסור לאשר את האסימון המזהה, או אחריו. מיוצג באמצעות זמן Unix (שניות של מספר שלם).
iat always השעה שבה הונפק האסימון המזהה. מיוצג בזמן Unix (שניות של מספר שלם).
iss always המזהה של מנפיק התגובה. תמיד https://accounts.google.com או accounts.google.com לאסימונים מזהים של Google.
sub always מזהה של המשתמש, שייחודי לכל חשבונות Google ולא נעשה בו שימוש חוזר. לחשבון Google יכולות להיות כמה כתובות אימייל בנקודות זמן שונות, אבל הערך sub לעולם לא משתנה. שימוש ב-sub באפליקציה בתור מפתח המזהה הייחודי של המשתמש. אורך מקסימלי של 255 תווי ASCII תלויי אותיות רישיות.
at_hash גיבוב (hash) של אסימון גישה. מספק אימות שאסימון הגישה מקושר לאסימון הזהות. אם האסימון המזהה מונפק עם ערך access_token בתהליך השרת, ההצהרה הזו תמיד תיכלל. אפשר להשתמש בהצהרה הזו כמנגנון חלופי להגנה מפני מתקפות זיוף של בקשות בין אתרים, אבל אם פועלים לפי שלב 1 ושלב 3 אין צורך לאמת את אסימון הגישה.
azp client_id של המציג המורשה. ההצהרה הזו נדרשת רק כשהגורם שמבקש את האסימון המזהה לא זהה מהקהל של האסימון המזהה. זה עשוי להיות המצב ב-Google לאפליקציות היברידיות, שבהן לאפליקציית אינטרנט ולאפליקציה ל-Android יש הרשאות OAuth 2.0 שונות client_id אבל הן חולקות את אותו פרויקט ב-Google APIs.
email זוהי כתובת האימייל של המשתמש. מסופק רק אם כללת את ההיקף email בבקשה שלך. ייתכן שהערך של התלונה הזו לא יהיה ייחודי לחשבון הזה, והוא עשוי להשתנות עם הזמן. לכן, אין להשתמש בערך הזה כמזהה הראשי לקישור לרשומת המשתמש שלך. בנוסף, אי אפשר להסתמך על הדומיין של ההצהרה email כדי לזהות משתמשים ב-Google Workspace או בארגונים מ-Cloud. במקום זאת, צריך להשתמש בהצהרה hd.
email_verified הערך הוא True אם כתובת האימייל של המשתמש אומתה. אחרת, הערך הוא False.
family_name שמות המשפחה או שמות המשפחה של המשתמשים. ייתכן שיסופק אם קיימת תלונה של name.
given_name השמות הפרטיים או השמות הפרטיים של המשתמש. ייתכן שיסופק אם קיימת תלונה של name.
hd הדומיין שמשויך לארגון של המשתמש ב-Google Workspace או ב-Cloud. השדה הזה מסופק רק אם המשתמש שייך לארגון ב-Google Cloud. צריך לסמן את ההצהרה הזו כשמגבילים את הגישה למשאב רק לחברים בדומיינים מסוימים. אם לא ההצהרה הזו לא תשויך לדומיין, החשבון לא שייך לדומיין באירוח של Google.
locale הלוקאל של המשתמש, מיוצג על ידי תג השפה BCP 47. ייתכן שיסופק כאשר קיימת תלונה מסוג name.
name השם המלא של המשתמש, בפורמט שניתן להצגה. ייתכן שיסופקו אם:
  • היקף הבקשה כלל את המחרוזת "profile"
  • האסימון המזהה מוחזר לאחר רענון האסימון

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

nonce הערך של nonce שסופק על ידי האפליקציה בבקשת האימות. צריך לאכוף את ההגנה מפני מתקפות חוזרות, באמצעות בדיקה שההגנה תוצג פעם אחת בלבד.
picture כתובת ה-URL של תמונת הפרופיל של המשתמש. ייתכן שיסופקו אם:
  • היקף הבקשה כלל את המחרוזת "profile"
  • האסימון המזהה מוחזר לאחר רענון האסימון

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

profile כתובת ה-URL של דף הפרופיל של המשתמש. ייתכן שיסופקו אם:
  • היקף הבקשה כלל את המחרוזת "profile"
  • האסימון המזהה מוחזר לאחר רענון האסימון

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

6. אימות המשתמש

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

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

נושאים מתקדמים

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

גישה לממשקי API אחרים של Google

אחד היתרונות של שימוש ב-OAuth 2.0 לצורך אימות הוא שהאפליקציה שלך יכולה לקבל הרשאה להשתמש בממשקי API אחרים של Google בשם המשתמש (כגון YouTube, Google Drive, יומן או אנשי קשר) בו-זמנית עם אימות המשתמש. כדי לעשות את זה, צריך לכלול בבקשת האימות את ההיקפים האחרים שאתם צריכים אל Google. לדוגמה, כדי להוסיף את קבוצת הגיל של המשתמש לבקשת האימות, צריך להעביר פרמטר היקף של openid email https://www.googleapis.com/auth/profile.agerange.read. המשתמש מתבקש לספק את הבקשה המתאימה במסך ההסכמה. אסימון הגישה שמקבלים בחזרה מ-Google מאפשר לגשת לכל ממשקי ה-API שקשורים להיקפי הגישה שביקשת וקיבלת.

אסימוני רענון

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

שיקולים:

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

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

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

למידע נוסף על הפרמטר prompt, ראו prompt בטבלה פרמטרים של URI לאימות.

פרמטרים של URI לאימות

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

פרמטר נדרש תיאור
client_id (נדרש) מחרוזת מזהה הלקוח שמקבלים מה- Credentials page API Console, כפי שמתואר במאמר קבלת פרטי כניסה של OAuth 2.0.
nonce (נדרש) ערך אקראי שנוצר על ידי האפליקציה שלך ומאפשר הגנה מפני הפעלה מחדש.
response_type (נדרש) אם הערך הוא code, מופעלת תהליך בסיסי של קוד הרשאה, שבו נדרשת POST לנקודת הקצה של האסימון כדי לקבל את האסימונים. אם הערך הוא token id_token או id_token token, מופעל זרם מרומז שמחייב שימוש ב-JavaScript ב-URI של ההפניה כדי לאחזר אסימונים ממזהה #fragment של ה-URI.
redirect_uri (נדרש) קביעת היעד שאליו תישלח התשובה. הערך של הפרמטר הזה חייב להתאים במדויק לאחד מערכי ההפניה המורשים שמוגדרים ב- API Console Credentials page (כולל סכמת HTTP או HTTPS, אותיות רישיות וסימן '/' בסוף, אם יש).
scope (נדרש)

פרמטר ההיקף חייב להתחיל בערך openid, ולאחר מכן לכלול את הערך profile, את הערך email או את שניהם.

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

אם קיים ערך מסוג email, האסימון המזהה כולל הצהרות של email ושל email_verified.

בנוסף להיקפים הספציפיים ל-OpenID, הארגומנט של ההיקף יכול לכלול גם ערכי היקף אחרים. כל ערכי ההיקף צריכים להיות מופרדים ברווחים. לדוגמה, אם רציתם לקבל גישה לכל קובץ ל-Google Drive של משתמש מסוים, הפרמטר של ההיקף יכול להיות openid profile email https://www.googleapis.com/auth/drive.file.

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

state (אופציונלי, אבל מומלץ בחום)

מחרוזת אטומה שעוברת עיגול עגול בפרוטוקול. כלומר, היא מוחזרת כפרמטר URI בתהליך הבסיסי, ובמזהה ה-URI #fragment בזרימה המרומזת.

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

access_type (לא חובה) הערכים המותרים הם offline ו-online. ההשפעה מתועדת בקטע גישה אופליין. אם מבקשים אסימון גישה, הלקוח לא מקבל אסימון רענון אלא אם צוין ערך של offline.
display (לא חובה) ערך של מחרוזת ASCII לציון האופן שבו שרת ההרשאות מציג את דפי ממשק המשתמש לאימות ולהסכמה. הערכים הבאים מצוינים ומאשרים על ידי שרתי Google, אבל אין להם כל השפעה על ההתנהגות שלהם: page, popup, touch ו-wap.
hd (לא חובה)

מייעלים את תהליך ההתחברות לחשבונות שבבעלות ארגון ב-Google Cloud. באמצעות הכללת הדומיין של הארגון ב-Google Cloud (לדוגמה, mycollege.edu) אפשר לציין שצריך לבצע אופטימיזציה של ממשק המשתמש לבחירת חשבונות עבור החשבונות באותו דומיין. כדי לבצע אופטימיזציה לחשבונות ארגוניים ב-Google Cloud בדרך כלל, במקום בדומיין ארגוני אחד ב-Google Cloud, מגדירים ערך של כוכבית (*): hd=*.

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

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

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

login_hint (לא חובה) כשהאפליקציה יודעת איזה משתמש היא מנסה לאמת, היא יכולה לספק את הפרמטר הזה כרמז לשרת האימות. העברת הרמז הזה מסתירה את בוחר החשבונות וממלאת מראש את תיבת האימייל בטופס הכניסה, או בוחרת את הסשן המתאים (אם המשתמש משתמש בכניסה עם מספר חשבונות), וכך אפשר למנוע בעיות שמתרחשות אם האפליקציה רושמת ביומן משתמש שגוי. הערך יכול להיות כתובת אימייל או המחרוזת sub, המקבילה למזהה Google של המשתמש.
prompt (לא חובה) רשימה של ערכי מחרוזת שמופרדים ברווחים. הערכים האלה מציינים אם שרת ההרשאות מבקש מהמשתמש אימות מחדש והסכמה. הערכים האפשריים הם:
  • none

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

  • consent

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

  • select_account

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

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

אימות אסימון מזהה

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

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

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

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

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

תהליך האימות של אסימון מזהה כולל כמה שלבים:

  1. מוודאים שהאסימון המזהה חתום כראוי על ידי המנפיק. אסימונים ש-Google מנפיקה נחתמים באמצעות אחד מהאישורים שנמצאים ב-URI שצוין בערך המטא-נתונים jwks_uri של מסמך Discovery.
  2. צריך לוודא שהערך של הצהרת iss באסימון המזהה שווה ל-https://accounts.google.com או ל-accounts.google.com.
  3. עליך לוודא שהערך של הצהרת aud באסימון המזהה זהה למזהה הלקוח של האפליקציה.
  4. מוודאים שמועד התפוגה (תלונה אחת (exp)) של האסימון המזהה עדיין לא חלף.
  5. אם ציינת בבקשה ערך של פרמטר hd, צריך לוודא שלאסימון המזהה יש הצהרת hd שתואמת לדומיין קביל שמשויך לארגון ב-Google Cloud.

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

השלב הראשון מורכב יותר, וכולל בדיקה של חתימה קריפטוגרפית. למטרות ניפוי באגים, אפשר להשתמש בנקודת הקצה tokeninfo של Google כדי להשוות לעיבוד המקומי שמוטמע בשרת או במכשיר. נניח שהערך של האסימון המזהה שלך הוא XYZ123. לאחר מכן, תצטרכו להסיר את ה-URI הזה https://oauth2.googleapis.com/tokeninfo?id_token=XYZ123. אם חתימת האסימון תקינה, התגובה תהיה המטען הייעודי (payload) של JWT בצורת אובייקט ה-JSON המפוענח.

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

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

קבלת פרטים מפרופיל המשתמש

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

  1. כדי לעמוד ב-OpenID, צריך לכלול את ערכי ההיקף openid profile בבקשת האימות.

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

    scope=openid%20profile%20email
  2. צריך להוסיף את אסימון הגישה לכותרת ההרשאה ולשלוח בקשת GET מסוג HTTPS לנקודת הקצה של פרטי המשתמש. צריך לאחזר את האסימון ממסמך הגילוי באמצעות ערך המטא-נתונים userinfo_endpoint. תגובת פרטי המשתמש כוללת מידע על המשתמש, כפי שמתואר ב-OpenID Connect Standard Claims ואת ערך המטא-נתונים claims_supported של מסמך Discovery. יכול להיות שהמשתמשים או הארגונים שלהם יבחרו אם לספק או לעכב שדות מסוימים, ולכן יכול להיות שלא תקבלו מידע לגבי כל שדה לגבי תחומי הגישה המורשים שלכם.

מסמך הגילוי

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

כדי לפשט את ההטמעה ולהגביר את הגמישות, OpenID Connect מאפשר להשתמש ב"מסמך Discovery" – מסמך JSON שנמצא במיקום ידוע שמכיל צמדי מפתח/ערך, שמספקים פרטים על התצורה של ספק OpenID Connect, כולל מזהי URI של ההרשאות, האסימון, הביטול, פרטי המשתמש ונקודות הקצה של מפתחות ציבוריים. ניתן לאחזר את מסמך הגילוי עבור שירות OpenID Connect של Google מ:

https://accounts.google.com/.well-known/openid-configuration

כדי להשתמש בשירותי OpenID Connect של Google, צריך לקודד בתוך האפליקציה את ה-URI של מסמך Discovery-document (https://accounts.google.com/.well-known/openid-configuration). האפליקציה מאחזרת את המסמך, מחילה את כללי השמירה במטמון בתגובה ואז מאחזרת ממנה מזהי URI של נקודות קצה לפי הצורך. לדוגמה, כדי לאמת משתמש, הקוד יאחזר את ערך המטא-נתונים authorization_endpoint (https://accounts.google.com/o/oauth2/v2/auth בדוגמה למטה) בתור ה-URI הבסיסי עבור בקשות אימות שנשלחות אל Google.

הנה דוגמה למסמך כזה. שמות השדות הם אלה שצוינו ב-OpenID Connect Discovery 1.0 (יש לעיין במסמך הזה כדי להבין את המשמעויות שלו). הערכים להמחשה בלבד ועשויים להשתנות, אם כי הם מועתקים מגרסה עדכנית של מסמך Google Discovery בפועל:

{
  "issuer": "https://accounts.google.com",
  "authorization_endpoint": "https://accounts.google.com/o/oauth2/v2/auth",
  "device_authorization_endpoint": "https://oauth2.googleapis.com/device/code",
  "token_endpoint": "https://oauth2.googleapis.com/token",
  "userinfo_endpoint": "https://openidconnect.googleapis.com/v1/userinfo",
  "revocation_endpoint": "https://oauth2.googleapis.com/revoke",
  "jwks_uri": "https://www.googleapis.com/oauth2/v3/certs",
  "response_types_supported": [
    "code",
    "token",
    "id_token",
    "code token",
    "code id_token",
    "token id_token",
    "code token id_token",
    "none"
  ],
  "subject_types_supported": [
    "public"
  ],
  "id_token_signing_alg_values_supported": [
    "RS256"
  ],
  "scopes_supported": [
    "openid",
    "email",
    "profile"
  ],
  "token_endpoint_auth_methods_supported": [
    "client_secret_post",
    "client_secret_basic"
  ],
  "claims_supported": [
    "aud",
    "email",
    "email_verified",
    "exp",
    "family_name",
    "given_name",
    "iat",
    "iss",
    "locale",
    "name",
    "picture",
    "sub"
  ],
  "code_challenge_methods_supported": [
    "plain",
    "S256"
  ]
}

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

ספריות לקוח

ספריות הלקוח הבאות מפשטות את ההטמעה של OAuth 2.0 באמצעות שילוב עם מסגרות פופולריות:

תאימות ל-OpenID Connect

מערכת האימות OAuth 2.0 של Google תומכת בתכונות הנדרשות של מפרט OpenID Connect Core. כל לקוח שמיועד לעבוד עם OpenID Connect צריך לפעול בצורה הדדית עם השירות הזה (למעט OpenID Request Object).