토큰 모델 사용

google.accounts.oauth2 자바스크립트 라이브러리를 사용하면 사용자 동의를 요청하는 메시지를 표시하고 사용자 데이터 작업을 위한 액세스 토큰을 얻을 수 있습니다. 이 API는 OAuth 2.0 암시적 권한 부여 흐름을 기반으로 하며 REST 및 CORS를 사용하여 Google API를 직접 호출하거나 JavaScript용 Google API 클라이언트 라이브러리 (gapi.client라고도 함)를 사용하여 더 복잡한 API에 간단하고 유연하게 액세스할 수 있도록 설계되었습니다.

브라우저에서 보호되는 사용자 데이터에 액세스하기 전에 사이트의 사용자는 Google의 웹 기반 계정 선택기, 로그인, 동의 프로세스를 트리거하고 마지막으로 Google의 OAuth 서버 문제를 트리거하고 웹 앱에 액세스 토큰을 반환합니다.

토큰 기반 승인 모델에서는 사용자별 갱신 토큰을 백엔드 서버에 저장할 필요가 없습니다.

이전 클라이언트 측 웹 애플리케이션용 OAuth 2.0 가이드에서 다루는 기법 대신 여기에 설명된 접근 방식을 따르는 것이 좋습니다.

설정

Google API 클라이언트 ID 가져오기 가이드에 설명된 단계에 따라 클라이언트 ID를 찾거나 만듭니다. 다음으로 Google API를 호출할 사이트의 페이지에 클라이언트 라이브러리를 추가합니다. 마지막으로 토큰 클라이언트를 초기화합니다. 일반적으로 클라이언트 라이브러리의 onload 핸들러 내에서 이 작업을 실행합니다.

토큰 클라이언트 초기화

initTokenClient()를 호출하여 웹 앱의 클라이언트 ID로 새 토큰 클라이언트를 초기화합니다. 선택적으로 사용자가 액세스해야 하는 하나 이상의 범위 목록을 포함할 수 있습니다.

const client = google.accounts.oauth2.initTokenClient({
  client_id: 'YOUR_GOOGLE_CLIENT_ID',
  scope: 'https://www.googleapis.com/auth/calendar.readonly',
  callback: (response) => {
    ...
  },
});

OAuth 2.0 토큰 흐름 트리거

requestAccessToken() 메서드를 사용하여 토큰 UX 흐름을 트리거하고 액세스 토큰을 가져옵니다. Google은 사용자에게 다음과 같은 메시지를 표시합니다.

  • 계정을 선택하고
  • Google 계정에 로그인합니다(아직 로그인하지 않은 경우).
  • 웹 앱이 요청된 각 범위에 액세스하는 데 동의합니다.

사용자 동작이 토큰 흐름(<button onclick="client.requestAccessToken();">Authorize me</button>)을 트리거합니다.

그러면 Google은 사용자가 액세스 토큰과 사용자가 액세스 권한을 부여한 범위 목록이 포함된 TokenResponse 또는 콜백 핸들러에 오류를 반환합니다.

사용자는 계정 선택기 또는 로그인 창을 닫을 수 있으며, 이 경우 콜백 함수가 호출되지 않습니다.

앱의 설계 및 사용자 환경은 Google의 OAuth 2.0 정책을 철저히 검토한 후에만 구현해야 합니다. 이러한 정책은 다중 범위 작업, 사용자 동의를 처리하는 시점과 방법 등에 대해 다룹니다.

증분 승인은 한 번에 모두 요청하는 대신 필요한 경우에만 범위를 사용하여 리소스 액세스를 요청하는 데 사용되는 정책 및 앱 설계 방법입니다. 사용자는 앱에서 요청한 개별 리소스 공유를 승인하거나 거부할 수 있습니다. 이를 세분화된 권한이라고 합니다.

이 프로세스 중에 Google은 요청된 각 범위를 개별적으로 나열하여 사용자 동의를 요청하고, 사용자는 앱과 공유할 리소스를 선택합니다. 마지막으로 콜백 함수를 호출하여 액세스 토큰과 사용자 승인 범위를 반환합니다. 그런 다음 앱은 세분화된 권한을 사용하여 가능한 다양한 결과를 안전하게 처리합니다.

증분 승인

웹 앱의 경우 다음 두 가지 상위 수준 시나리오는 다음을 사용한 점진적 승인을 보여줍니다.

  • 리소스에 대한 동적 액세스와 함께 XMLHttpRequest를 자주 사용하는 단일 페이지 Ajax 앱
  • 여러 개의 웹페이지, 리소스가 페이지별로 구분되고 관리됩니다.

이 두 시나리오는 디자인 고려사항과 방법을 설명하기 위해 제시되었으며 앱에 동의를 구축하는 방법에 관한 포괄적인 권장사항을 제공하기 위한 것이 아닙니다. 실제 앱에서는 이러한 기법의 변형이나 조합을 사용할 수 있습니다.

아약스

requestAccessToken()를 여러 번 호출하고 OverridableTokenClientConfig 객체의 scope 매개변수를 사용하여 필요할 때 그리고 필요할 때만 개별 범위를 요청함으로써 앱에 증분 승인 지원을 추가합니다. 이 예에서는 사용자 동작이 접힌 콘텐츠 섹션을 펼친 후에만 리소스가 요청되고 표시됩니다.

Ajax 앱
페이지 로드 시 토큰 클라이언트를 초기화합니다.
        const client = google.accounts.oauth2.initTokenClient({
          client_id: 'YOUR_GOOGLE_CLIENT_ID',
          callback: "onTokenResponse",
        });
      
사용자 동작을 통해 동의를 요청하고 액세스 토큰을 받은 다음 `+` 를 클릭하여 엽니다.

읽을 문서

최근 문서 표시

          client.requestAccessToken(
            overrideConfig = ({
               scope = 'https://www.googleapis.com/auth/documents.readonly'
             })
           );
        

예정된 이벤트

캘린더 정보 표시

          client.requestAccessToken(
            overrideConfig = ({
               scope = 'https://www.googleapis.com/auth/calendar.readonly'
             })
           );
        

사진 표시

          client.requestAccessToken(
            overrideConfig = ({
               scope = 'https://www.googleapis.com/auth/photoslibrary.readonly'
             })
           );
        

requestAccessToken을 호출할 때마다 사용자 동의가 트리거되고, 앱은 사용자가 확장하기로 선택한 섹션에 필요한 리소스에만 액세스할 수 있으므로 사용자 선택을 통한 리소스 공유가 제한됩니다.

여러 웹페이지

점진적 승인을 설계할 때 여러 페이지를 사용하여 페이지를 로드하는 데 필요한 범위만 요청하므로 복잡성이 줄어들고 사용자 동의를 얻고 액세스 토큰을 가져오기 위해 여러 번 호출해야 할 필요성이 줄어듭니다.

다중 페이지 앱
웹페이지 코드
1페이지. 읽을 문서
  const client = google.accounts.oauth2.initTokenClient({
    client_id: 'YOUR_GOOGLE_CLIENT_ID',
    callback: "onTokenResponse",
    scope: 'https://www.googleapis.com/auth/documents.readonly',
  });
  client.requestAccessToken();
          
2페이지. 예정된 이벤트
  const client = google.accounts.oauth2.initTokenClient({
    client_id: 'YOUR_GOOGLE_CLIENT_ID',
    callback: "onTokenResponse",
    scope: 'https://www.googleapis.com/auth/calendar.readonly',
  });
  client.requestAccessToken();
          
3페이지. 사진 캐러셀
  const client = google.accounts.oauth2.initTokenClient({
    client_id: 'YOUR_GOOGLE_CLIENT_ID',
    callback: "onTokenResponse",
    scope: 'https://www.googleapis.com/auth/photoslibrary.readonly',
  });
  client.requestAccessToken();
          

각 페이지는 로드 시 initTokenClient()requestAccessToken()를 호출하여 필요한 범위를 요청하고 액세스 토큰을 얻습니다. 이 시나리오에서는 개별 웹페이지가 사용자 기능과 리소스를 범위별로 명확하게 구분하는 데 사용됩니다. 실제 상황에서는 개별 페이지가 여러 관련 범위를 요청할 수 있습니다.

세분화된 권한

세분화된 권한은 모든 시나리오에서 동일하게 처리됩니다. requestAccessToken()가 콜백 함수를 호출하고 액세스 토큰이 반환된 후 사용자가 hasGrantedAllScopes() 또는 hasGrantedAnyScope()를 사용하여 요청된 범위를 승인했는지 확인합니다. 예를 들면 다음과 같습니다.

const client = google.accounts.oauth2.initTokenClient({
  client_id: 'YOUR_GOOGLE_CLIENT_ID',
  scope: 'https://www.googleapis.com/auth/calendar.readonly \
          https://www.googleapis.com/auth/documents.readonly \
          https://www.googleapis.com/auth/photoslibrary.readonly',
  callback: (tokenResponse) => {
    if (tokenResponse && tokenResponse.access_token) {
      if (google.accounts.oauth2.hasGrantedAnyScope(tokenResponse,
          'https://www.googleapis.com/auth/photoslibrary.readonly')) {
        // Look at pictures
        ...
      }
      if (google.accounts.oauth2.hasGrantedAllScopes(tokenResponse,
          'https://www.googleapis.com/auth/calendar.readonly',
          'https://www.googleapis.com/auth/documents.readonly')) {
        // Meeting planning and review documents
        ...
      }
    }
  },
});

이전 세션 또는 요청에서 이전에 수락한 권한 부여도 응답에 포함됩니다. 사용자 동의 기록은 사용자 및 클라이언트 ID별로 유지되고 initTokenClient() 또는 requestAccessToken()를 여러 번 호출해도 유지됩니다. 기본적으로 사용자 동의는 사용자가 웹사이트를 처음 방문하고 새 범위를 요청할 때만 필요하지만 토큰 클라이언트 구성 객체에서 prompt=consent를 사용하여 페이지를 로드할 때마다 사용자 동의를 요청할 수 있습니다.

토큰 작업

토큰 모델에서 액세스 토큰은 OS나 브라우저에 의해 저장되지 않습니다. 대신 페이지 로드 시 또는 이어서 버튼 누르기와 같은 사용자 동작을 통해 requestAccessToken() 호출을 트리거하여 새 토큰을 먼저 가져옵니다.

Google API에 REST 및 CORS 사용

액세스 토큰은 REST 및 CORS를 사용하여 Google API에 인증된 요청을 수행하는 데 사용될 수 있습니다. 이를 통해 사용자가 로그인하고 동의를 부여할 수 있으며 Google에서 액세스 토큰을 발급하고 사이트에서 사용자 데이터를 사용할 수 있습니다.

이 예시에서는 tokenRequest()에서 반환된 액세스 토큰을 사용하여 로그인한 사용자의 예정된 캘린더 이벤트를 확인합니다.

var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://www.googleapis.com/calendar/v3/calendars/primary/events');
xhr.setRequestHeader('Authorization', 'Bearer ' + tokenResponse.access_token);
xhr.send();

자세한 내용은 CORS를 사용하여 Google API에 액세스하는 방법을 참고하세요.

다음 섹션에서는 더 복잡한 API와 쉽게 통합하는 방법을 설명합니다.

Google API JavaScript 라이브러리로 작업하기

토큰 클라이언트는 JavaScript용 Google API 클라이언트 라이브러리에서 작동합니다. 아래의 코드 스니펫을 참조하세요.

const client = google.accounts.oauth2.initTokenClient({
  client_id: 'YOUR_GOOGLE_CLIENT_ID',
  scope: 'https://www.googleapis.com/auth/calendar.readonly',
  callback: (tokenResponse) => {
    if (tokenResponse && tokenResponse.access_token) {
      gapi.client.setApiKey('YOUR_API_KEY');
      gapi.client.load('calendar', 'v3', listUpcomingEvents);
    }
  },
});

function listUpcomingEvents() {
  gapi.client.calendar.events.list(...);
}

토큰 만료

설계상 액세스 토큰은 수명이 짧습니다. 액세스 토큰이 사용자 세션이 끝나기 전에 만료되면 버튼 누르기와 같은 사용자 기반 이벤트에서 requestAccessToken()를 호출하여 새 토큰을 가져옵니다.

google.accounts.oauth2.revoke 메서드를 호출하여 앱에 부여된 모든 범위의 리소스에 대한 사용자 동의와 액세스 권한을 삭제합니다. 이 권한을 취소하려면 유효한 액세스 토큰이 필요합니다.

google.accounts.oauth2.revoke('414a76cb127a7ece7ee4bf287602ca2b56f8fcbf7fcecc2cd4e0509268120bd7', done => {
    console.log(done);
    console.log(done.successful);
    console.log(done.error);
    console.log(done.error_description);
  });