OpenID Connect

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

הגדרת OAuth 2.0

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

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

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

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

אפשר גם לראות את מזהה הלקוח וסוד הלקוח בדף Clients במסוף Cloud:

  1. עוברים אל הדף "לקוחות".
  2. לוחצים על שם הלקוח או על סמל העריכה (). מזהה הלקוח והסוד מופיעים בחלק העליון של הדף.

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

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

כדי ליצור, להציג או לערוך את כתובות ה-URI להפניה אוטומטית של פרטי כניסה מסוימים ל-OAuth 2.0:

  1. עוברים אל הדף "לקוחות".
  2. לוחצים על הלקוח.
  3. צפייה או עריכה של כתובות ה-URI להפניה אוטומטית.

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

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

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

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

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

  1. פותחים את הדף Branding במסוף Google Cloud.
  2. אם מתבקשים, בוחרים פרויקט או יוצרים פרויקט חדש.
  3. ממלאים את הטופס ולוחצים על שמירה.

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

דוגמה לדף הסכמה
איור 1. צילום מסך של דף ההסכמה

גישה לשירות

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

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

אימות המשתמש

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

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

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

תהליך בשרת

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

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

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

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

אפשרות טובה אחת לטוקן מצב היא מחרוזת של כ-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

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

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

  • client_id, שאותו מקבלים מדף הלקוחות במסוף Cloud.
  • ‫response_type, שבבקשה בסיסית של הרשאה באמצעות קוד צריך להיות code. (מידע נוסף זמין בכתובת response_type.)
  • ‫scope, שבבקשה בסיסית צריך להיות openid email. (מידע נוסף זמין בכתובת scope.)
  • ‫redirect_uri צריכה להיות נקודת הקצה של HTTP בשרת שלכם שתקבל את התגובה מ-Google. הערך חייב להיות זהה לאחד ממזהי ה-URI המורשים להפניה אוטומטית של לקוח OAuth 2.0, שהגדרתם בדף Credentials במסוף Cloud. אם הערך הזה לא תואם ל-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//developers.google.com/oauthplayground&
 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://developers.google.com/oauthplayground?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

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

שדות
code קוד ההרשאה שמוחזר מהבקשה הראשונית.
client_id מזהה הלקוח שקיבלתם מדף הלקוחות במסוף Cloud, כפי שמתואר במאמר קבלת פרטי כניסה ל-OAuth 2.0.
client_secret סוד הלקוח שמקבלים מדף הלקוחות במסוף Cloud, כפי שמתואר במאמר קבלת פרטי כניסה ל-OAuth 2.0.
redirect_uri כתובת URI מורשית להפניה אוטומטית של client_id שצוין בדף Clients במסוף Cloud, כמו שמתואר בקטע הגדרת כתובת 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//developers.google.com/oauthplayground&
grant_type=authorization_code

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

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

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

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

טוקן של מזהה הוא JWT (טוקן אינטרנט מסוג JSON), כלומר אובייקט 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 תמיד הקהל שאמור להשתמש בטוקן של המזהה. הוא חייב להיות אחד ממזהי הלקוח ב-OAuth 2.0 של האפליקציה.
exp תמיד זמן התפוגה שבו או אחריו אסור לקבל את טוקן של מזהה. מיוצג בזמן של ראשית זמן יוניקס (Unix epoch) (מספר שלם של שניות).
iat תמיד הזמן שבו הונפק הטוקן של המזהה. מיוצג בזמן של ראשית זמן יוניקס (Unix epoch) (מספר שלם של שניות).
iss תמיד מזהה המנפיק של מנפיק התגובה. תמיד https://accounts.google.com או accounts.google.com לטוקנים של מזהי Google.
sub תמיד מזהה של המשתמש, ייחודי לכל חשבונות Google ולעולם לא נעשה בו שימוש חוזר. לחשבון Google יכולות להיות כמה כתובות אימייל בנקודות זמן שונות, אבל הערך של sub אף פעם לא משתנה. משתמשים ב-sub באפליקציה כמפתח המזהה הייחודי של המשתמש. האורך המקסימלי הוא 255 תווים ב-ASCII, תלוי אותיות רישיות.
amr מערך JSON של מחרוזות שמזהות את שיטות האימות שמשמשות לכניסה לחשבון Google. אם הוא קיים, הוא כולל אחד או יותר מהערכים האפשריים הבאים של [IANA.AMR]:
  • hwk נעשה שימוש במפתח חומרה
  • ‫mfa הושלם אימות רב-שלבי
  • נעשה שימוש בסיסמה של pwd
  • sms הודעת SMS שימשה לאימות
  • swk נעשה שימוש במפתח תוכנה כמו מפתח גישה
  • tel בוצע אימות באמצעות שיחת טלפון
מוצג רק כשההצהרה amr נכללת בבקשת האימות ומופעלת בהגדרות.
auth_time השעה שבה בוצע אימות המשתמש, מספר JSON שמייצג את מספר השניות שחלפו מאז ראשית זמן יוניקס (Unix epoch) (1 בינואר 1970, 00:00:00 UTC). הערך הזה מסופק כשהטענה auth_time נכללת בבקשת האימות ומופעלת בהגדרות.
at_hash גיבוב (hash) של טוקן גישה. מאמת שטוקן הגישה מקושר לטוקן הזהות. אם טוקן של מזהה מונפק עם ערך access_token בתהליך השרת, ההצהרה הזו תמיד נכללת. אפשר להשתמש בטענה הזו כמנגנון חלופי להגנה מפני התקפות של זיוף בקשות בין אתרים, אבל אם פועלים לפי שלב 1 ושלב 3, אין צורך לאמת את טוקן הגישה.
azp client_id של המציג המורשה. ההצהרה הזו נדרשת רק אם הגורם שמבקש את טוקן של מזהה הוא לא אותו קהל של טוקן של מזהה. זה יכול לקרות ב-Google באפליקציות היברידיות, שבהן לאפליקציית אינטרנט ולאפליקציה ל-Android יש client_id שונה של OAuth 2.0, אבל הן משתפות את אותו פרויקט של Google APIs.
email זוהי כתובת האימייל של המשתמש. מופיע רק אם כללתם את ההיקף email בבקשה. יכול להיות שהערך של ההצהרה הזו לא ייחודי לחשבון הזה, והוא עשוי להשתנות עם הזמן. לכן, אל תשתמשו בערך הזה כמזהה הראשי לקישור לרשומת המשתמש שלכם. בנוסף, אי אפשר להסתמך על הדומיין של ההצהרה email כדי לזהות משתמשים של ארגונים ב-Google Workspace או ב-Cloud. במקום זאת, צריך להשתמש בהצהרה hd.
email_verified ‫True אם כתובת האימייל של המשתמש אומתה, אחרת False.
family_name שם המשפחה של המשתמש. יכול להיות שהשדה הזה יופיע כשיש טענת נכוֹנוּת (claim) מסוג name.
given_name השם הפרטי של המשתמש. יכול להיות שהשדה הזה יופיע כשיש טענת נכוֹנוּת (claim) מסוג name.
hd הדומיין שמשויך לארגון של המשתמש ב-Google Workspace או ב-Cloud. מוצג רק אם המשתמש שייך לארגון ב-Google Cloud. צריך לבדוק את הטענה הזו כשמגבילים את הגישה למשאב רק לחברים בדומיינים מסוימים. אם הטענה הזו לא קיימת, סימן שהחשבון לא שייך לדומיין שמתארח ב-Google.
locale הלוקאל של המשתמש, שמיוצג על ידי תג שפה בתקן BCP 47. יכול להיות שהשדה הזה יופיע כשיש טענת נכוֹנוּת (claim) מסוג name.
name השם המלא של המשתמש, בפורמט שניתן להציג. יכול להיות שהערך הזה יופיע במקרים הבאים:
  • היקף הבקשה כלל את המחרוזת "פרופיל"
  • טוקן של מזהה מוחזר מרענון טוקן

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

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

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

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

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

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

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

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

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

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

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

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

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

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

שיקולים:

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

מידע נוסף זמין במאמר רענון של טוקן גישה (גישה אופליין).

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

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

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

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

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

הפרמטר 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 יכול להגביר את הוודאות שהחיבור הנכנס הוא תוצאה של בקשת אימות שהאפליקציה שלך יזמה. אם יוצרים מחרוזת אקראית או מקודדים את ה-hash של מצב לקוח מסוים (למשל, קובץ cookie) במשתנה state הזה, אפשר לאמת את התגובה כדי לוודא שהבקשה והתגובה הגיעו מאותו דפדפן. כך אפשר להגן מפני התקפות כמו זיוף בקשות בין אתרים.

access_type (אופציונלי) הערכים המותרים הם offline ו-online. ההשפעה מתועדת בקטע גישה אופליין. אם מתבקש טוקן גישה, הלקוח לא מקבל טוקן רענון אלא אם צוין הערך offline.
claims (אופציונלי) הפרמטר claims משמש כדי לציין שדה אופציונלי אחד או יותר שצריך לכלול בנקודת הקצה userinfo או בסוגי התגובות של טוקן המזהה של בקשת האימות. הערך הוא אובייקט JSON שמכיל את סוג התגובה ואת ההצהרות המבוקשות. השרתים של Google מקבלים את בקשות התביעה הבאות:
בקשות תלונה
amr בקשת השיטה שבה השתמשו כשהמשתמש אומת בפעם האחרונה. כדי להחזיר את amr כשדה בתגובה של טוקן המזהה, צריך לכלול את פרמטר הבקשה claims: claims={"id_token":{"amr":{"essential":true}}} צריך להפעיל את האפשרות בהגדרות.
auth_time בקשת השעה שבה המשתמש אומת בפעם האחרונה. כדי להחזיר את auth_time כשדה בתגובה של טוקן המזהה, צריך לכלול את פרמטר הבקשה claims: claims={"id_token":{"auth_time":{"essential":true}}} צריך להפעיל את האפשרות בהגדרות.
display (אופציונלי) ערך מחרוזת ASCII שמציין איך שרת ההרשאות מציג את דפי ממשק המשתמש של האימות וההסכמה. הערכים הבאים מצוינים ומתקבלים על ידי שרתי Google, אבל לא משפיעים על ההתנהגות של תהליך הפרוטוקול: page,‏ popup,‏ touch ו-wap.
hd (אופציונלי)

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

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

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

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

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

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

  • consent

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

  • select_account

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

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

hl (אופציונלי) תג שפה בתקן BCP 47 שמשמש לציון שפת התצוגה של מסכי הכניסה, Account Chooser ומסכי ההסכמה. אם לא מציינים את הפרמטר הזה, השפה שמוגדרת כברירת מחדל היא השפה שמוגדרת בחשבון Google או בדפדפן של המשתמש. לדוגמה, כדי לבקש את ממשק המשתמש באנגלית בריטית, מגדירים את הפרמטר לערך en-GB.

אימות של טוקן של מזהה

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

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

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

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

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

אימות של טוקן של מזהה דורש כמה שלבים:

  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. מוסיפים את אסימון הגישה לכותרת ההרשאה ושולחים בקשת HTTPS GET לנקודת הקצה של פרטי המשתמש, שאותה צריך לאחזר ממסמך Discovery באמצעות ערך המטא-נתונים userinfo_endpoint. התגובה של userinfo כוללת מידע על המשתמש, כמו שמתואר ב-OpenID Connect Standard Claims ובערך המטא-נתונים claims_supported של מסמך Discovery. המשתמשים או הארגונים שלהם יכולים לבחור אם לספק או לא לספק שדות מסוימים, כך שיכול להיות שלא תקבלו מידע בכל שדה בהיקפי הגישה המורשים שלכם.

מסמך Discovery

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

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

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

כדי להשתמש בשירותי OpenID Connect של Google, צריך להוסיף את ה-URI של מסמך Discovery‏ (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 (המשמעויות שלהם מפורטות במסמך הזה). הערכים הם להמחשה בלבד ועשויים להשתנות, למרות שהם מועתקים מגרסה עדכנית של מסמך Discovery של Google:

{
  "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).