OpenID Connect

ממשקי ה-API של OAuth 2.0 של Google יכולים לשמש גם לאימות וגם להרשאה. במסמך הזה מתוארת הטמעת OAuth 2.0 לאימות, שתואמת למפרט של OpenID Connect ומאושרת על ידי OpenID. התיעוד שמופיע במאמר שימוש ב-OAuth 2.0 לגישה לממשקי API של Google חל גם על השירות הזה. אם ברצונך לחקור את הפרוטוקול הזה באופן אינטראקטיבי, מומלץ להשתמש במגרש המשחקים של Google OAuth 2.0. כדי לקבל עזרה בנושא 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, כולל מזהה לקוח וסוד לקוח.

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

לחלופין, צפה בזיהוי הלקוח ובסוד הלקוח שלך מדף האישורים ב API Console :

  1. Go to the Credentials page.
  2. לחץ על שם האישור שלך או על סמל העיפרון ( ). קוד זיהוי הלקוח וסודך נמצאים בראש העמוד.

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

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

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

  1. Go to the Credentials page.
  2. בקטע מזהי לקוח OAuth 2.0 בדף, לחץ על אישור.
  3. הצגה או עריכה של קבצי ה- URI המפנים מחדש.

אם אין קטע מזהי לקוח של OAuth 2.0 בדף האישורים, לפרויקט שלך אין אישורי 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, שתוכננו לשימוש בשיתוף הצהרות זהות באינטרנט.

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

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

זרימת שרת

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

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

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

עליך להגן על אבטחת המשתמשים שלך על ידי מניעת התקפות של זיוף בקשות. השלב הראשון הוא יצירת אסימון ייחודי של סשן ששומר את המצב בין האפליקציה שלך לבין הלקוח של המשתמש. בשלב מאוחר יותר תתאים את אסימון הסשן הייחודי הזה לתגובת האימות שהוחזרה על ידי שירות ההתחברות של Google OAuth, כדי לאמת שהמשתמש הוא זה ששלח את הבקשה ולא תוקף זדוני. האסימונים האלה מכונים לעיתים קרובות אסימונים מסוג Cross-Site Request Forgery (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 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 יש client_id OAuth 2.0 שונה, אבל יש להן פרויקט Google APIs שונה.
email זוהי כתובת האימייל של המשתמש. יכול להיות שהערך הזה לא ייחודי למשתמש הזה והוא לא מתאים לשימוש כמפתח ראשי. השדה הזה מופיע רק אם ההיקף כולל את הערך של ההיקף email.
email_verified הערך הוא True אם כתובת האימייל של המשתמש אומתה. אחרת, הערך False.
family_name שמות המשפחה או שמות המשפחה של המשתמשים. ייתכן שתקבלו תלונה אם תישלח תלונה על הפרת זכויות יוצרים ב-name.
given_name השמות הפרטיים או השמות הפרטיים של המשתמש. ייתכן שתקבלו תלונה אם תישלח תלונה על הפרת זכויות יוצרים ב-name.
hd הדומיין שמשויך לארגון של המשתמש ב-Google Cloud. השירות מסופק רק אם המשתמש שייך לארגון ב-Google Cloud.
locale הלוקאל של המשתמש, מיוצג על ידי תג השפה BCP 47. ייתכן שתקבלו תלונה על הפרת זכויות יוצרים עם תלונה של name.
name השם המלא של המשתמש, בפורמט שניתן להצגה. יכול להיות שהנתונים יסופקו כאשר:
  • היקף הבקשה כלל את המחרוזת "profile"
  • האסימון המזהה מוחזר מרענון האסימון

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

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

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

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

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

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

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

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

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

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

מסמך 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).