אימות Looker API באמצעות OAuth

‫Looker משתמש ב-OAuth כדי לאפשר לאפליקציות לקוח של OAuth לבצע אימות ב-Looker API בלי לחשוף את מזהי הלקוחות וסודות הלקוחות לדפדפן שמפעיל את אפליקציית הלקוח של OAuth.

אפליקציות אינטרנט שמשתמשות ב-OAuth צריכות לעמוד בדרישות הבאות:

  • אימות באמצעות OAuth זמין רק ב-Looker API 4.0.
  • כדי שמשתמשי האפליקציה יוכלו לבצע אימות ב-Looker, צריך קודם לרשום את לקוחות OAuth ב-Looker באמצעות ה-API.
  • אפליקציות לקוח חייבות להשתמש ב-HTTPS לכל הבקשות ל-Looker API. אפליקציות לקוח שרוצות להשתמש בממשקי ה-API של SubtleCrypto שהדפדפן מספק חייבות להתארח ב-HTTPS.

תמיכה ב-CORS ב-Looker API

אפשר להפעיל את Looker API בדפדפן ובמקורות שונים באמצעות פרוטוקול שיתוף משאבים בין מקורות (CORS). אלה הדרישות לתמיכה ב-CORS ב-Looker:

  • רק מקורות שמופיעים ברשימת ההיתרים של הדומיינים המוטמעים יכולים לקרוא ל-API באמצעות CORS.

  • אפשר להשתמש רק בטוקני גישה שהתקבלו מ-OAuth או מקריאה לנקודת קצה ל-API‏ /login כדי לבצע קריאות ל-Looker API באמצעות CORS.

סקירה כללית על אימות OAuth

סקירה כללית של תהליך האימות באמצעות OAuth:

  1. רושמים את אפליקציית לקוח OAuth במכונה של Looker.
  2. מוסיפים את המקור של אפליקציית הלקוח של OAuth לרשימת ההיתרים של הדומיינים המוטמעים בשביל הקריאה ל-API להחלפת קוד ובשביל כל קריאה עוקבת ל-CORS API.

  3. כשאפליקציית הלקוח של OAuth מנסה לאמת משתמש, צריך להפנות את כתובת ה-URL של הדפדפן לנקודת הקצה (endpoint) של /auth בשם המארח של ממשק המשתמש של Looker (ולא בשם המארח של Looker API). לדוגמה, https://instance_name.looker.com.

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

  5. באמצעות קוד ההרשאה שמוחזר בהפניה לכתובת אחרת של OAuth, אפליקציית הלקוח של OAuth צריכה לבצע קריאה לנקודת הקצה (endpoint) של /token בשם המארח של Looker API, לדוגמה, https://instance_name.looker.com:19999. שם המארח של ה-API יכול להיות זהה לשם המארח של ממשק המשתמש של Looker או שונה ממנו. נקודת הקצה /token קיימת רק במארח של Looker API, ונקודת הקצה /auth קיימת רק במארח של ממשק המשתמש של Looker.

  6. אם קוד ההרשאה שמועבר לנקודת הקצה (endpoint) של /token תקף, Looker מחזיר access_token של API שמופעל לבקשות API של CORS מהדומיין של אפליקציית לקוח OAuth.

רישום של אפליקציית לקוח OAuth

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

אדמינים ב-Looker יכולים לרשום ולנהל אפליקציות לקוח מותאמות אישית של OAuth ישירות בחלונית Admin ב-Looker, בדף Manage OAuth Clients (Admin > Authentication > Manage OAuth clients). הממשק הזה מאפשר לאדמינים לבצע את המשימות הבאות:

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

הוראות מפורטות לרישום לקוחות בהתאמה אישית בחלונית הניהול זמינות בדף התיעוד הגדרות אדמין – ניהול לקוחות OAuth.

רישום פרוגרמטי באמצעות ה-API

לחלופין, אדמינים יכולים לרשום אפליקציית לקוח OAuth באופן פרוגרמטי על ידי קריאה ישירה לנקודת הקצה Register OAuth App או על ידי הפעלה שלה ב-Looker API Explorer. הפרמטרים כוללים:

  • ‫client_guid: מזהה מחרוזת ייחודי לאפליקציה (לא יכול להתחיל ב-com.looker.).
  • ‫redirect_uris: מערך של כתובות URI מורשות להחזרת קריאה, שבהן האפליקציה תקבל את ההפניה האוטומטית של OAuth ואת קוד ההרשאה.
  • ‫display_name: שם האפליקציה שמוצג למשתמשים.
  • ‫description: תיאור של אפליקציית הלקוח של OAuth.
  • ‫group_id (אופציונלי): המזהה המספרי של קבוצת Looker שרוצים להגביל את הגישה אליה.

התחברות של משתמש באמצעות OAuth

  1. מפנים את המשתמש לנקודת הקצה /auth במארח של ממשק המשתמש. לדוגמה:

    async function oauth_login() {
      const code_verifier = secure_random(32)
      const code_challenge = await sha256_hash(code_verifier)
      const params = {
        response_type: 'code',
        client_id: '123456',
        redirect_uri: 'https://mywebapp.com:3000/authenticated',
        scope: 'cors_api',
        state: '1235813',
        code_challenge_method: 'S256',
        code_challenge: code_challenge,
      }
      const url = `${base_url}?${new URLSearchParams(params).toString()}` // Replace base_url with your full Looker instance's UI host URL, plus the `/auth` endpoint.
      log(url)
    
      // Stash the code verifier we created in sessionStorage, which
      // will survive page loads caused by login redirects
      // The code verifier value is needed after the login redirect
      // to redeem the auth_code received for an access_token
      //
      sessionStorage.setItem('code_verifier', code_verifier)
    
      document.location = url
    }
    
    function array_to_hex(array) {
      return Array.from(array).map(b => b.toString(16).padStart(2,'0')).join('')
    }
    
    function secure_random(byte_count) {
      const array = new Uint8Array(byte_count);
      crypto.getRandomValues(array);
      return array_to_hex(array)
    }
    
    async function sha256_hash(message) {
      const msgUint8 = new TextEncoder().encode(message)
      const hashBuffer = await crypto.subtle.digest('SHA-256', msgUint8)
      return base64.urlEncode(hashBuffer))  // Refers to the implementation of base64.encode stored at https://gist.github.com/jhurliman/1250118
    }
    

    מערכת Looker תנסה לאמת את המשתמש באמצעות מערכת האימות שמוגדרת במכונה של Looker.

    • אם המשתמש כבר מחובר ל-Looker בדפדפן הנוכחי (כלומר, יש מצב פעיל של קובץ Cookie של התחברות), המשתמש לא יתבקש להזין את פרטי הכניסה שלו.
    • אם זו הפעם הראשונה שהמשתמש הזה מתחבר באמצעות אפליקציית הלקוח הזו של OAuth, ‏ Looker יציג דף גילוי נאות ואישור שהמשתמש צריך לאשר ולקבל. יוצג הטקסט מהפרמטר description שבו השתמשתם כשרשמתם את האפליקציה. התיאור צריך לציין מה האפליקציה מתכוונת לעשות עם חשבון Looker של המשתמש. כשהמשתמשת לוחצת על אישור, הדף מפנה אותה לאפליקציה redirect_uri.
    • אם המשתמש כבר מחובר ל-Looker בדפדפן הנוכחי וכבר אישר את דף הגילוי הנאות, ההתחברות באמצעות OAuth מתבצעת באופן מיידי בלי הפרעה חזותית.
  2. ‫Looker API יחזיר הפניה לכתובת אחרת של OAuth לאפליקציית הלקוח של OAuth. שומרים את קוד ההרשאה שמופיע בפרמטר ה-URI. דוגמה ל-URI להפניה אוטומטית של OAuth:

    https://mywebapp.com:3000/authenticated?&code=asdfasdfassdf&state=...
    

    קוד ההרשאה מופיע אחרי &code= ב-URI. בדוגמה הזו, קוד ההרשאה הוא asdfasdfassdf.

  3. שולחים בקשה לאחזור מהרשת לנקודת הקצה /token ב-Looker API, ומעבירים את קוד ההרשאה ואת פרטי האפליקציה. לדוגמה:

    async function redeem_auth_code(response_str) {
      const params = new URLSearchParams(response_str)
      const auth_code = params.get('code')
    
      if (!auth_code) {
        log('ERROR: No authorization code in response')
        return
      }
      log(`auth code received: ${auth_code}`)
      log(`state: ${params.get('state')}`)
    
      const code_verifier = sessionStorage.getItem('code_verifier')
      if (!code_verifier) {
        log('ERROR: Missing code_verifier in session storage')
        return
      }
      sessionStorage.removeItem('code_verifier')
      const response = await
      fetch('https://mycompany.looker.com:19999/api/token', {  // This is the URL of your Looker instance's API web service
        method: 'POST',
        mode: 'cors',    // This line is required so that the browser will attempt a CORS request.
        body: stringify({
          grant_type: 'authorization_code',
          client_id: '123456',
          redirect_uri: 'https://mywebapp.com:3000/authenticated',
          code: auth_code,
          code_verifier: code_verifier,
        }),
        headers: {
          'x-looker-appid': 'Web App Auth & CORS API Demo', // This header is optional.
          'Content-Type': 'application/json;charset=UTF-8'  // This header is required.
        },
      }).catch((error) => {
        log(`Error: ${error.message}`)
      })
    
      const info = await response.json()
      log(`/api/token response: ${stringify(info)}`)
    
      // Store the access_token and other info,
      // which in this example is done in sessionStorage
    
      const expires_at = new Date(Date.now() + (info.expires_in * 1000))
      info.expires_at = expires_at
      log(`Access token expires at ${expires_at.toLocaleTimeString()} local time.`)
      sessionStorage.setItem('access_info', stringify(info))
      access_info = info
    }
    

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

    האדמין ב-Looker יכול לבטל את כל האסימונים במערכת הזו בכל שלב.