OpenID Connect

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

הגדרת OAuth 2.0

כדי שהאפליקציה שלכם תוכל להשתמש במערכת האימות של Google מסוג OAuth 2.0 לכניסת משתמשים, עליכם להגדיר פרטי כניסה ל-OAuth 2.0 ב- Google API Console , להגדיר URI להפניה אוטומטית (redirect) ולשנות (אופציונלי) את פרטי המיתוג שיוצגו למשתמשים במסך ההסכמה שלהם. אפשר גם להשתמש ב- 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 שולחת תשובות לבקשות האימות.

כדי ליצור, להציג או לערוך את כתובות ה- 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 Playground, ולכן היא לא כוללת פרטי מיתוג שייקבעו ב- API Console).

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

גישה לשירות

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

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

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

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

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

עומס העבודה של אסימון מזהה

אסימון מזהה הוא אובייקט 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 תמיד מועד התפוגה, שבו אסור לקבל את אסימון המזהה או אחריו. מיוצג בזמן יוניקס (שניות שלמים).
iat תמיד השעה שבה הונפק האסימון המזהה. מיוצג בזמן יוניקס (שניות שלמות).
iss תמיד מזהה המנפיק של המנפיק של התשובה. תמיד https://accounts.google.com או accounts.google.com לאסימונים מזהים של Google.
sub תמיד מזהה של המשתמש, ייחודי לכל חשבונות 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 כדי לזהות משתמשים בארגונים של 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, או לפחות לאכלס מראש הרבה מהשדות הנדרשים בטופס ההרשמה. בנוסף למידע שמופיע באסימון המזהה, אפשר לקבל פרטים נוספים על פרופיל המשתמש בנקודות הקצה של פרופיל המשתמש.

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

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

שיקולים:

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

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

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

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

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

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

פרמטר חובה תיאור
client_id (נדרש) מחרוזת מזהה הלקוח שמקבלים מ- API Console Credentials page, כפי שמתואר בקטע קבלת פרטי כניסה ל-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 קיים, אסימון המזהה כולל טענות נכונות (claims) של email ושל email_verified.

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

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

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

מחרוזת אטומה שמתבצעת בה חזרה (round-trip) בפרוטוקול. כלומר, היא מוחזרת כפרמטר 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=*.

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

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

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

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

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

  • consent

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

  • select_account

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

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

תיקוף של אסימון מזהה

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

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

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

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

אחד מהיתרונות של אסימונים מזהים הוא העובדה שאפשר להעביר אותם בין רכיבים שונים באפליקציה. הרכיבים האלה יכולים להשתמש באסימון מזהה כמנגנון אימות קל לאימות האפליקציה והמשתמש. עם זאת, כדי שתוכלו להשתמש במידע באסימון המזהה או להסתמך עליו כטענת נכוֹנוּת (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. אם החתימה על האסימון תקינה, התגובה תהיה המטען הייעודי של ה-JWT בפורמט אובייקט JSON מפוענח.

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

מסמך Discovery

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

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

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

כדי להשתמש בשירותי OpenID Connect של Google, צריך להטמיע את ה-URI של מסמך הגילוי (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"
  ]
}

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

ספריות לקוח

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

תאימות ל-OpenID Connect

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