OAuth를 사용한 Looker API 인증

Looker는 OAuth를 사용하여 OAuth 클라이언트 애플리케이션을 실행하는 브라우저에 클라이언트 ID와 클라이언트 보안 비밀번호를 노출하지 않고 Looker API에 인증합니다.

OAuth를 사용하는 웹 애플리케이션은 다음 요구사항을 충족해야 합니다.

  • Looker API 4.0에서만 OAuth를 사용한 인증을 사용할 수 있습니다.
  • OAuth 클라이언트 애플리케이션을 먼저 API를 사용하여 Looker에 등록해야 애플리케이션 사용자가 Looker에 인증할 수 있습니다.
  • 클라이언트 애플리케이션은 모든 Looker API 요청에 HTTPS를 사용해야 합니다. 브라우저에서 제공하는 SubtleCrypto API를 사용하려는 클라이언트 애플리케이션은 HTTPS 호스팅이어야 합니다.

Looker API CORS 지원

Looker API는 브라우저 및 출처 간 교차 출처 리소스 공유(CORS) 프로토콜을 사용한 호출을 지원합니다. Looker CORS 지원에는 다음 요구사항이 있습니다.

  • 삽입된 도메인 허용 목록에 나열된 출처에서만 CORS를 사용하여 API를 호출할 수 있습니다.
  • OAuth 또는 /login API 엔드포인트 호출에서 얻은 액세스 토큰만 CORS를 사용하여 Looker API를 호출할 때 사용할 수 있습니다.

    CORS 요청을 사용하여 /login API 엔드포인트를 호출할 수 없습니다. CORS 요청을 사용하여 Looker API를 호출하려는 클라이언트 애플리케이션은 OAuth를 사용하여 사용자 로그인 수행에 설명된 OAuth 로그인 프로세스를 사용하거나 애플리케이션 서버 또는 비CORS API 호출에서 토큰을 가져와야 합니다.

OAuth 인증 개요

OAuth 인증 프로세스 개요는 다음과 같습니다.

  1. Looker API에 OAuth 클라이언트 애플리케이션을 등록합니다.
  2. 코드 교환 API 호출 및 후속 CORS API 호출의 삽입된 도메인 허용 목록에 OAuth 클라이언트 애플리케이션의 출처를 추가합니다.
  3. OAuth 클라이언트 애플리케이션에서 사용자 인증을 시도할 때 Looker API 호스트 이름이 아닌 Looker UI 호스트 이름의 /auth 엔드포인트로 브라우저 URL을 리디렉션합니다. 예를 들면 https://instance_name.looker.com입니다.
  4. 사용자가 인증되고 Looker에 로그인하면 Looker가 즉시 OAuth 클라이언트 애플리케이션에 OAuth 리디렉션을 반환합니다. 사용자가 기기와 브라우저에서 Looker에 로그인하지 않은 경우 Looker 로그인 화면이 표시되고 일반 인증 프로토콜을 사용하여 Looker 사용자 계정에 로그인하라는 메시지가 표시됩니다.
  5. OAuth 클라이언트 애플리케이션은 OAuth 리디렉션에서 반환된 승인 코드를 사용하여 Looker API 호스트 이름의 /token 엔드포인트를 호출합니다(예: https://instance_name.looker.com:19999). API 호스트 이름은 Looker UI 호스트 이름과 같거나 다를 수 있습니다. /token 엔드포인트는 Looker API 호스트에만 존재하고 /auth 엔드포인트는 Looker UI 호스트에만 존재합니다.
  6. /token 엔드포인트로 전달된 승인 코드가 유효하면 Looker가 OAuth 클라이언트 애플리케이션 도메인의 CORS API 요청에 사용 설정된 API access_token을 반환합니다.

OAuth 클라이언트 애플리케이션 등록

OAuth를 사용하여 Looker API에 인증하려는 모든 OAuth 클라이언트 애플리케이션을 먼저 Looker 인스턴스에 등록해야 Looker에서 액세스를 승인합니다. OAuth 클라이언트 애플리케이션을 등록하려면 다음 안내를 따르세요.

  1. Looker 인스턴스에서 API 탐색기를 엽니다.
  2. 버전 드롭다운 메뉴를 사용하여 4.0 - 안정화 버전의 API를 선택합니다.
  3. Auth 메서드에서 register_oauth_client_app() API 엔드포인트를 찾습니다. 검색 필드에서 'oauth app'을 검색할 수도 있습니다. register_oauth_client_app()을 사용하여 Looker에 OAuth 클라이언트 애플리케이션을 등록할 수 있습니다. 실행 버튼을 클릭하고 API 탐색기에 매개변수를 입력하고 실행을 다시 클릭하여 OAuth 클라이언트 애플리케이션을 등록하거나 프로그래매틱 방식으로 register_oauth_client_app() API 엔드포인트를 사용합니다. 필수 register_oauth_client_app() 매개변수는 다음과 같습니다.

    • client_guid: 애플리케이션의 전역 고유 ID
    • redirect_uri: 애플리케이션이 승인 코드가 포함된 OAuth 리디렉션을 수신하는 URI
    • display_name: 애플리케이션 사용자에게 표시되는 애플리케이션 이름
    • description: 사용자가 처음으로 애플리케이션에서 로그인할 때 공개 정보 및 확인 페이지에 표시되는 애플리케이션 설명

    client_guidredirect_uri 매개변수의 값은 OAuth 클라이언트 애플리케이션이 제공하는 값과 정확히 일치해야 합니다. 그렇지 않으면 인증이 거부됩니다.

OAuth를 사용한 사용자 로그인 수행

  1. 사용자를 UI 호스트의 /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에 이미 로그인한 경우(라이브 로그인 쿠키 상태가 있음) 로그인 사용자 인증 정보를 입력하라는 메시지가 사용자에게 표시되지 않습니다.
    • 이 사용자가 OAuth 클라이언트 애플리케이션을 사용하여 처음 로그인하는 경우 사용자가 확인하고 수락할 수 있도록 공개 문구와 확인 페이지가 표시됩니다. 애플리케이션이 등록될 때 사용된 description 매개변수의 텍스트가 표시됩니다. 이 설명은 애플리케이션이 사용자의 Looker 계정으로 수행할 작업을 나타내야 합니다. 사용자가 수락을 클릭하면 페이지가 애플리케이션 redirect_uri로 리디렉션됩니다.
    • 사용자가 현재 브라우저에서 이미 Looker에 로그인하고 공개 페이지를 확인했다면 OAuth 로그인은 즉시 표시되며 시각적인 방해도 없습니다.
  2. Looker API는 OAuth 클라이언트 애플리케이션에 OAuth 리디렉션을 반환합니다. URI 매개변수에 나열된 승인 코드를 저장합니다. 다음은 OAuth 리디렉션 URI의 예시입니다.

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

    승인 코드는 URI에서 &code= 뒤에 표시됩니다. 이 예시에서 승인 코드는 asdfasdfassdf입니다.

  3. Looker API의 /token 엔드포인트에 웹 요청을 보내 승인 코드와 애플리케이션 정보를 전달합니다. 예를 들면 다음과 같습니다.

    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 클라이언트 애플리케이션에 API access_token를 제공합니다. 응답에는 refresh_token도 포함됩니다. 이를 통해 나중에 사용자 상호작용 없이 새 access_token을 가져올 수 있습니다. refresh_token 수명은 한 달입니다. refresh_token을 안전하게 보관합니다.

    이 시스템의 모든 토큰은 언제든지 Looker 관리자가 취소할 수 있습니다.