웹 서버 애플리케이션에 OAuth 2.0 사용

이 문서는 웹 서버 애플리케이션이 Google API 클라이언트 라이브러리 또는 Google OAuth 2.0 엔드 포인트를 사용하여 Google API에 액세스하기 위해 OAuth 2.0 인증을 구현하는 방법을 설명합니다.

OAuth 2.0을 통해 사용자는 사용자 이름, 비밀번호 및 기타 정보를 비공개로 유지하면서 특정 데이터를 애플리케이션과 공유 할 수 있습니다. 예를 들어 애플리케이션은 OAuth 2.0을 사용하여 사용자로부터 Google 드라이브에 파일을 저장할 수있는 권한을 얻을 수 있습니다.

이 OAuth 2.0 흐름은 특히 사용자 인증을위한 것입니다. 기밀 정보를 저장하고 상태를 유지할 수있는 애플리케이션을 위해 설계되었습니다. 적절하게 인증 된 웹 서버 애플리케이션은 사용자가 애플리케이션과 상호 작용하는 동안 또는 사용자가 애플리케이션을 떠난 후에 API에 액세스 할 수 있습니다.

웹 서버 애플리케이션은 특히 사용자 별 데이터가 아닌 프로젝트 기반 데이터에 액세스하기 위해 Cloud API를 호출 할 때 API 요청을 승인하기 위해 서비스 계정 을 자주 사용합니다. 웹 서버 응용 프로그램은 사용자 인증과 함께 서비스 계정을 사용할 수 있습니다.

클라이언트 라이브러리

이 페이지의 언어 별 예는 Google API 클라이언트 라이브러리 를 사용하여 OAuth 2.0 승인을 구현합니다. 코드 샘플을 실행하려면 먼저 해당 언어의 클라이언트 라이브러리를 설치해야합니다.

Google API 클라이언트 라이브러리를 사용하여 애플리케이션의 OAuth 2.0 흐름을 처리하면 클라이언트 라이브러리는 애플리케이션이 자체적으로 처리해야하는 많은 작업을 수행합니다. 예를 들어 애플리케이션이 저장된 액세스 토큰을 사용하거나 새로 고칠 수있는시기와 애플리케이션이 동의를 다시 받아야하는시기를 결정합니다. 또한 클라이언트 라이브러리는 올바른 리디렉션 URL을 생성하고 액세스 토큰에 대한 인증 코드를 교환하는 리디렉션 처리기를 구현하는 데 도움이됩니다.

클라이언트 라이브러리는 다음 언어로 사용할 수 있습니다.

전제 조건

프로젝트에 API 사용

Google API를 호출하는 모든 애플리케이션은 API Console에서 해당 API를 활성화해야합니다.

프로젝트에 API를 사용하려면 다음을 수행하십시오.

  1. Google API Console의 Open the API Library.
  2. If prompted, select a project, or create a new one.
  3. API Library은 제품군 및 인기도별로 그룹화 된 사용 가능한 모든 API를 나열합니다. 활성화하려는 API가 목록에 표시되지 않으면 검색을 사용하여 찾거나 해당 API가 속한 제품군에서 모두보기를 클릭합니다.
  4. 활성화 할 API를 선택한 다음 활성화 버튼을 클릭합니다.
  5. If prompted, enable billing.
  6. If prompted, read and accept the API's Terms of Service.

인증 자격 증명 만들기

OAuth 2.0을 사용하여 Google API에 액세스하는 모든 애플리케이션에는 Google의 OAuth 2.0 서버에 대한 애플리케이션을 식별하는 인증 자격 증명이 있어야합니다. 다음 단계에서는 프로젝트에 대한 자격 증명을 만드는 방법을 설명합니다. 그러면 애플리케이션은 사용자 인증 정보를 사용하여 해당 프로젝트에 대해 활성화 한 API에 액세스 할 수 있습니다.

  1. Go to the Credentials page.
  2. 사용자 인증 정보 만들기> OAuth 클라이언트 ID를 클릭합니다.
  3. 웹 애플리케이션 애플리케이션 유형을 선택하십시오.
  4. 양식을 작성하고 만들기를 클릭합니다. PHP, Java, Python, Ruby, .NET과 같은 언어 및 프레임 워크를 사용하는 애플리케이션은 승인 된 리디렉션 URI를 지정해야합니다. 리디렉션 URI는 OAuth 2.0 서버가 응답을 보낼 수있는 끝점입니다. 이러한 엔드 포인트는 Google의 유효성 검사 규칙을 준수해야합니다.

    테스트를 위해 http://localhost:8080 과 같이 로컬 시스템을 참조하는 URI를 지정할 수 있습니다. 이를 염두에두고이 문서의 모든 예제는 http://localhost:8080 을 리디렉션 URI로 사용합니다.

    애플리케이션이 페이지의 다른 리소스에 인증 코드를 노출하지 않도록 앱의 인증 엔드 포인트디자인 하는 것이 좋습니다.

자격 증명을 만든 후 API Console에서 client_secret.json 파일을 다운로드합니다. 애플리케이션 만 액세스 할 수있는 위치에 파일을 안전하게 저장하십시오.

액세스 범위 식별

범위를 사용하면 애플리케이션이 필요한 리소스에 대한 액세스 만 요청할 수 있으며 사용자는 애플리케이션에 부여하는 액세스 양을 제어 할 수 있습니다. 따라서 요청 된 범위의 수와 사용자 동의를 얻을 가능성 사이에 역관계가있을 수 있습니다.

OAuth 2.0 승인 구현을 시작하기 전에 앱에 액세스 권한이 필요한 범위를 식별하는 것이 좋습니다.

또한 애플리케이션이 컨텍스트에서 사용자 데이터에 대한 액세스를 요청하는 증분 인증 프로세스를 통해 인증 범위에 대한 액세스를 요청하는 것이 좋습니다. 이 모범 사례는 사용자가 응용 프로그램에서 요청하는 액세스 권한이 필요한 이유를보다 쉽게 ​​이해할 수 있도록 도와줍니다.

OAuth 2.0 API 범위 문서에는 Google API에 액세스하는 데 사용할 수있는 전체 범위 목록이 포함되어 있습니다.

언어 별 요구 사항

이 문서의 코드 샘플을 실행하려면 Google 계정, 인터넷 액세스 및 웹 브라우저가 필요합니다. API 클라이언트 라이브러리 중 하나를 사용하는 경우 아래의 언어 별 요구 사항도 참조하세요.

PHP

이 문서에서 PHP 코드 샘플을 실행하려면 다음이 필요합니다.

  • 명령 줄 인터페이스 (CLI) 및 JSON 확장이 설치된 PHP 5.4 이상.
  • Composer 종속성 관리 도구.
  • PHP 용 Google API 클라이언트 라이브러리 :

    php composer.phar require google/apiclient:^2.0

파이썬

이 문서에서 Python 코드 샘플을 실행하려면 다음이 필요합니다.

  • Python 2.6 이상
  • pip 패키지 관리 도구.
  • Python 용 Google API 클라이언트 라이브러리 :
    pip install --upgrade google-api-python-client
  • 사용자 인증을위한 google-auth , google-auth-oauthlibgoogle-auth-httplib2 .
    pip install --upgrade google-auth google-auth-oauthlib google-auth-httplib2
  • Flask Python 웹 애플리케이션 프레임 워크입니다.
    pip install --upgrade flask
  • requests HTTP 라이브러리입니다.
    pip install --upgrade requests

루비

이 문서에서 Ruby 코드 샘플을 실행하려면 다음이 필요합니다.

  • Ruby 2.2.2 이상
  • Ruby 용 Google API 클라이언트 라이브러리 :

    gem install google-api-client
  • Sinatra Ruby 웹 애플리케이션 프레임 워크.

    gem install sinatra

HTTP / REST

OAuth 2.0 엔드 포인트를 직접 호출하기 위해 라이브러리를 설치할 필요가 없습니다.

OAuth 2.0 액세스 토큰 얻기

다음 단계는 애플리케이션이 Google의 OAuth 2.0 서버와 상호 작용하여 사용자를 대신하여 API 요청을 수행하기 위해 사용자의 동의를 얻는 방법을 보여줍니다. 사용자 승인이 필요한 Google API 요청을 실행하려면 애플리케이션에 이러한 동의가 있어야합니다.

아래 목록은 이러한 단계를 간단하게 요약합니다.

  1. 애플리케이션은 필요한 권한을 식별합니다.
  2. 애플리케이션은 요청 된 권한 목록과 함께 사용자를 Google로 리디렉션합니다.
  3. 사용자는 애플리케이션에 권한을 부여할지 여부를 결정합니다.
  4. 응용 프로그램은 사용자가 결정한 내용을 알아냅니다.
  5. 사용자가 요청 된 권한을 부여한 경우 애플리케이션은 사용자를 대신하여 API 요청을 수행하는 데 필요한 토큰을 검색합니다.

1 단계 : 승인 매개 변수 설정

첫 번째 단계는 승인 요청을 만드는 것입니다. 이 요청은 애플리케이션을 식별하는 매개 변수를 설정하고 사용자가 애플리케이션에 부여 할 권한을 정의합니다.

  • OAuth 2.0 인증 및 승인에 Google 클라이언트 라이브러리를 사용하는 경우 이러한 매개 변수를 정의하는 개체를 만들고 구성합니다.
  • Google OAuth 2.0 엔드 포인트를 직접 호출하는 경우 URL을 생성하고 해당 URL에 매개 변수를 설정합니다.

아래 탭은 웹 서버 애플리케이션에 대해 지원되는 인증 매개 변수를 정의합니다. 언어 별 예에서는 클라이언트 라이브러리 또는 권한 부여 라이브러리를 사용하여 해당 매개 변수를 설정하는 개체를 구성하는 방법도 보여줍니다.

PHP

아래 코드 스 니펫은 승인 요청에서 매개 변수를 정의하는 Google_Client() 객체를 만듭니다.

이 객체는 client_secret.json 파일의 정보를 사용하여 애플리케이션을 식별합니다. (해당 파일에 대한 자세한 내용은 인증 자격 증명 만들기를 참조하세요.) 또한 객체는 애플리케이션이 액세스 권한을 요청하는 범위와 Google OAuth 2.0 서버의 응답을 처리 할 애플리케이션의 인증 엔드 포인트에 대한 URL을 식별합니다. 마지막으로 코드는 선택적 access_typeinclude_granted_scopes 매개 변수를 설정합니다.

예를 들어 다음 코드는 사용자의 Google 드라이브에 대한 읽기 전용 오프라인 액세스를 요청합니다.

$client = new Google_Client();
$client->setAuthConfig('client_secret.json');
$client->addScope(Google_Service_Drive::DRIVE_METADATA_READONLY);
$client->setRedirectUri('http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback.php');
// offline access will give you both an access and refresh token so that
// your app can refresh the access token without user interaction.
$client->setAccessType('offline');
// Using "consent" ensures that your application always receives a refresh token.
// If you are not using offline access, you can omit this.
$client->setApprovalPrompt("consent");
$client->setIncludeGrantedScopes(true);   // incremental auth

요청은 다음 정보를 지정합니다.

매개 변수
client_id 필수

애플리케이션의 클라이언트 ID입니다. 이 값은 API Console Credentials page에서 찾을 수 있습니다.

PHP에서 setAuthConfig 함수를 호출하여 client_secret.json 파일에서 인증 자격 증명을로드합니다.

$client = new Google_Client();
$client->setAuthConfig('client_secret.json');
redirect_uri 필수

사용자가 인증 흐름을 완료 한 후 API 서버가 사용자를 리디렉션하는 위치를 결정합니다. 이 값은 클라이언트의 API Console Credentials page에서 구성한 OAuth 2.0 클라이언트에 대해 승인 된 리디렉션 URI 중 하나와 정확히 일치해야합니다. 이 값이 제공된 client_id 대해 승인 된 리디렉션 URI와 일치하지 않으면 redirect_uri_mismatch 오류가 발생합니다.

http 또는 https 체계, 대소 문자 및 후행 슬래시 ( ' / ')가 모두 일치해야합니다.

PHP에서이 값을 설정하려면 setRedirectUri 함수를 호출하십시오. 제공된 client_id 유효한 리디렉션 URI를 지정해야합니다.

$client->setRedirectUri('https://oauth2.example.com/code');
scope 필수

애플리케이션이 사용자를 대신하여 액세스 할 수있는 리소스를 식별하는 공백으로 구분 된 범위 목록입니다. 이 값은 Google이 사용자에게 표시하는 동의 화면을 알려줍니다.

범위를 사용하면 애플리케이션이 필요한 리소스에 대한 액세스 만 요청할 수 있으며 사용자는 애플리케이션에 부여하는 액세스 양을 제어 할 수 있습니다. 따라서 요청 된 범위의 수와 사용자 동의를 얻을 가능성 사이에는 반비례 관계가 있습니다.

PHP에서이 값을 설정하려면 addScope 함수를 호출합니다.

$client->addScope(Google_Service_Drive::DRIVE_METADATA_READONLY);

가능한 경우 애플리케이션에서 컨텍스트에서 권한 부여 범위에 대한 액세스를 요청하는 것이 좋습니다. 증분 인증을 통해 컨텍스트에서 사용자 데이터에 대한 액세스를 요청하면 사용자가 애플리케이션에서 요청하는 액세스가 필요한 이유를 더 쉽게 이해할 수 있습니다.

access_type 추천

사용자가 브라우저에 없을 때 애플리케이션이 액세스 토큰을 새로 고칠 수 있는지 여부를 나타냅니다. 유효한 매개 변수 값은 기본값 인 onlineoffline 입니다.

사용자가 브라우저에 없을 때 애플리케이션에서 액세스 토큰을 새로 고쳐야하는 경우 값을 offline 설정하십시오. 이 문서의 뒷부분에서 설명하는 액세스 토큰을 새로 고치는 방법입니다. 이 값은 애플리케이션이 처음으로 인증 코드를 토큰으로 교환 할 때 새로 고침 토큰 액세스 토큰을 반환하도록 Google 인증 서버에 지시합니다.

PHP에서이 값을 설정하려면 setAccessType 함수를 호출하십시오.

$client->setAccessType('offline');
state 추천

애플리케이션이 권한 요청과 권한 서버의 응답 사이의 상태를 유지하기 위해 사용하는 문자열 값을 지정합니다. 서버는 사용자가 애플리케이션의 액세스 요청에 동의하거나 거부 한 후 redirect_uri 의 URL 쿼리 구성 요소 ( ? )에 name=value 쌍으로 전송 한 정확한 값을 반환합니다.

이 매개 변수는 사용자를 애플리케이션의 올바른 리소스로 안내하고, nonce를 전송하고, 교차 사이트 요청 위조를 완화하는 등 여러 목적으로 사용할 수 있습니다. redirect_uri 를 추측 할 수 있으므로 state 값을 사용하면 들어오는 연결이 인증 요청의 결과라는 확신을 높일 수 있습니다. 임의의 문자열을 생성하거나 쿠키의 해시 또는 클라이언트의 상태를 캡처하는 다른 값을 인코딩하는 경우 요청과 응답이 동일한 브라우저에서 시작되었는지 추가로 확인하여 교차 사이트와 같은 공격에 대한 보호를 제공하기 위해 응답을 검증 할 수 있습니다. 위조 요청. state 토큰을 만들고 확인하는 방법에 대한 예제는 OpenID Connect 설명서를 참조하십시오.

PHP에서이 값을 설정하려면 setState 함수를 호출하십시오.

$client->setState($sample_passthrough_value);
include_granted_scopes 선택 과목

애플리케이션이 증분 인증을 사용하여 컨텍스트의 추가 범위에 대한 액세스를 요청할 수 있도록합니다. 이 매개 변수의 값을 true 설정하고 권한 부여 요청이 부여 된 경우 새 액세스 토큰은 사용자가 이전에 애플리케이션 액세스 권한을 부여한 모든 범위도 포함합니다. 예시는 증분 인증 섹션을 참조하세요.

PHP에서이 값을 설정하려면 setIncludeGrantedScopes 함수를 호출합니다.

$client->setIncludeGrantedScopes(true);
login_hint 선택 과목

애플리케이션이 인증하려는 사용자를 알고있는 경우이 매개 변수를 사용하여 Google 인증 서버에 힌트를 제공 할 수 있습니다. 서버는 힌트를 사용하여 로그인 양식의 이메일 필드를 미리 채우거나 적절한 다중 로그인 세션을 선택하여 로그인 흐름을 단순화합니다.

매개 변수 값을 사용자의 Google ID와 동일한 이메일 주소 또는 sub 식별자로 설정합니다.

PHP에서이 값을 설정하려면 setLoginHint 함수를 호출하십시오.

$client->setLoginHint('None');
prompt 선택 과목

사용자에게 표시 할 공백으로 구분되고 대소 문자를 구분하는 프롬프트 목록입니다. 이 매개 변수를 지정하지 않으면 프로젝트에서 처음으로 액세스를 요청할 때만 사용자에게 메시지가 표시됩니다. 자세한 내용은 재동의 요청 을 참조하십시오.

PHP에서이 값을 설정하려면 setApprovalPrompt 함수를 호출합니다.

$client->setApprovalPrompt('consent');

가능한 값은 다음과 같습니다.

none 인증 또는 동의 화면을 표시하지 마십시오. 다른 값과 함께 지정하면 안됩니다.
consent 사용자에게 동의를 요청합니다.
select_account 사용자에게 계정을 선택하라는 메시지를 표시합니다.

파이썬

다음 코드 스 니펫은 google-auth-oauthlib.flow 모듈을 사용하여 승인 요청을 구성합니다.

이 코드는 인증 자격 증명만든 후 다운로드 한 client_secret.json 파일의 정보를 사용하여 애플리케이션을 식별하는 Flow 객체를 구성합니다. 이 객체는 또한 애플리케이션이 액세스 권한을 요청하는 범위와 Google의 OAuth 2.0 서버의 응답을 처리 할 애플리케이션의 인증 엔드 포인트에 대한 URL을 식별합니다. 마지막으로 코드는 선택적 access_typeinclude_granted_scopes 매개 변수를 설정합니다.

예를 들어 다음 코드는 사용자의 Google 드라이브에 대한 읽기 전용 오프라인 액세스를 요청합니다.

import google.oauth2.credentials
import google_auth_oauthlib.flow

# Use the client_secret.json file to identify the application requesting
# authorization. The client ID (from that file) and access scopes are required.
flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
    'client_secret.json',
    scopes=['https://www.googleapis.com/auth/drive.metadata.readonly'])

# Indicate where the API server will redirect the user after the user completes
# the authorization flow. The redirect URI is required. The value must exactly
# match one of the authorized redirect URIs for the OAuth 2.0 client, which you
# configured in the API Console. If this value doesn't match an authorized URI,
# you will get a 'redirect_uri_mismatch' error.
flow.redirect_uri = 'https://www.example.com/oauth2callback'

# Generate URL for request to Google's OAuth 2.0 server.
# Use kwargs to set optional request parameters.
authorization_url, state = flow.authorization_url(
    # Enable offline access so that you can refresh an access token without
    # re-prompting the user for permission. Recommended for web server apps.
    access_type='offline',
    # Enable incremental authorization. Recommended as a best practice.
    include_granted_scopes='true')

요청은 다음 정보를 지정합니다.

매개 변수
client_id 필수

애플리케이션의 클라이언트 ID입니다. 이 값은 API Console Credentials page에서 찾을 수 있습니다.

Python에서 from_client_secrets_file 메서드를 호출하여 client_secret.json 파일에서 클라이언트 ID를 검색합니다. (원래 클라이언트 비밀 파일에 표시되었지만 파일 자체에 액세스하지 않는 클라이언트 구성을 전달하는 from_client_config 메소드를 사용할 수도 있습니다.)

flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
    'client_secret.json',
    scopes=['https://www.googleapis.com/auth/drive.metadata.readonly'])
redirect_uri 필수

사용자가 인증 흐름을 완료 한 후 API 서버가 사용자를 리디렉션하는 위치를 결정합니다. 이 값은 클라이언트의 API Console Credentials page에서 구성한 OAuth 2.0 클라이언트에 대해 승인 된 리디렉션 URI 중 하나와 정확히 일치해야합니다. 이 값이 제공된 client_id 대해 승인 된 리디렉션 URI와 일치하지 않으면 redirect_uri_mismatch 오류가 발생합니다.

http 또는 https 체계, 대소 문자 및 후행 슬래시 ( ' / ')가 모두 일치해야합니다.

Python에서이 값을 설정하려면 flow 객체의 redirect_uri 속성을 설정합니다.

flow.redirect_uri = 'https://oauth2.example.com/code'
scope 필수

애플리케이션이 사용자를 대신하여 액세스 할 수있는 리소스를 식별하는 범위 목록입니다. 이 값은 Google이 사용자에게 표시하는 동의 화면을 알려줍니다.

범위를 사용하면 애플리케이션이 필요한 리소스에 대한 액세스 만 요청할 수 있으며 사용자는 애플리케이션에 부여하는 액세스 양을 제어 할 수 있습니다. 따라서 요청 된 범위의 수와 사용자 동의를 얻을 가능성 사이에는 반비례 관계가 있습니다.

Python에서는 client_id 를 설정하는 데 사용하는 것과 동일한 방법을 사용하여 범위 목록을 지정합니다.

flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
    'client_secret.json',
    scopes=['https://www.googleapis.com/auth/drive.metadata.readonly'])

가능한 경우 애플리케이션에서 컨텍스트에서 권한 부여 범위에 대한 액세스를 요청하는 것이 좋습니다. 증분 인증을 통해 컨텍스트에서 사용자 데이터에 대한 액세스를 요청하면 사용자가 애플리케이션에서 요청하는 액세스가 필요한 이유를 더 쉽게 이해할 수 있습니다.

access_type 추천

사용자가 브라우저에 없을 때 애플리케이션이 액세스 토큰을 새로 고칠 수 있는지 여부를 나타냅니다. 유효한 매개 변수 값은 기본값 인 onlineoffline 입니다.

사용자가 브라우저에 없을 때 애플리케이션에서 액세스 토큰을 새로 고쳐야하는 경우 값을 offline 설정하십시오. 이 문서의 뒷부분에서 설명하는 액세스 토큰을 새로 고치는 방법입니다. 이 값은 애플리케이션이 처음으로 인증 코드를 토큰으로 교환 할 때 새로 고침 토큰 액세스 토큰을 반환하도록 Google 인증 서버에 지시합니다.

Python에서는 flow.authorization_url 메서드를 호출 할 때 access_type 을 키워드 인수로 지정하여 access_type 매개 변수를 설정합니다.

authorization_url, state = flow.authorization_url(
    access_type='offline',
    include_granted_scopes='true')
state 추천

애플리케이션이 권한 요청과 권한 서버의 응답 사이의 상태를 유지하기 위해 사용하는 문자열 값을 지정합니다. 서버는 사용자가 애플리케이션의 액세스 요청에 동의하거나 거부 한 후 redirect_uri 의 URL 쿼리 구성 요소 ( ? )에 name=value 쌍으로 전송 한 정확한 값을 반환합니다.

이 매개 변수는 사용자를 애플리케이션의 올바른 리소스로 안내하고, nonce를 전송하고, 교차 사이트 요청 위조를 완화하는 등 여러 목적으로 사용할 수 있습니다. redirect_uri 를 추측 할 수 있으므로 state 값을 사용하면 들어오는 연결이 인증 요청의 결과라는 확신을 높일 수 있습니다. 임의의 문자열을 생성하거나 쿠키의 해시 또는 클라이언트의 상태를 캡처하는 다른 값을 인코딩하는 경우 요청과 응답이 동일한 브라우저에서 시작되었는지 추가로 확인하여 교차 사이트와 같은 공격에 대한 보호를 제공하기 위해 응답을 검증 할 수 있습니다. 위조 요청. state 토큰을 만들고 확인하는 방법에 대한 예제는 OpenID Connect 설명서를 참조하십시오.

Python에서는 flow.authorization_url 메서드를 호출 할 때 state 를 키워드 인수로 지정하여 state 매개 변수를 설정합니다.

authorization_url, state = flow.authorization_url(
    access_type='offline',
    state=sample_passthrough_value,
    include_granted_scopes='true')
include_granted_scopes 선택 과목

애플리케이션이 증분 인증을 사용하여 컨텍스트의 추가 범위에 대한 액세스를 요청할 수 있습니다. 이 매개 변수의 값을 true 설정하고 권한 부여 요청이 부여 된 경우 새 액세스 토큰은 사용자가 이전에 애플리케이션 액세스 권한을 부여한 모든 범위도 포함합니다. 예시는 증분 인증 섹션을 참조하세요.

Python에서는 flow.authorization_url 메서드를 호출 할 때 include_granted_scopes 를 키워드 인수로 지정하여 include_granted_scopes 매개 변수를 설정합니다.

authorization_url, state = flow.authorization_url(
    access_type='offline',
    include_granted_scopes='true')
login_hint 선택 과목

애플리케이션이 인증하려는 사용자를 알고있는 경우이 매개 변수를 사용하여 Google 인증 서버에 힌트를 제공 할 수 있습니다. 서버는 힌트를 사용하여 로그인 양식의 이메일 필드를 미리 채우거나 적절한 다중 로그인 세션을 선택하여 로그인 흐름을 단순화합니다.

매개 변수 값을 사용자의 Google ID와 동일한 이메일 주소 또는 sub 식별자로 설정합니다.

Python에서 flow.authorization_url 메서드를 호출 할 때 login_hint 를 키워드 인수로 지정하여 login_hint 매개 변수를 설정합니다.

authorization_url, state = flow.authorization_url(
    access_type='offline',
    login_hint='None',
    include_granted_scopes='true')
prompt 선택 과목

사용자에게 표시 할 공백으로 구분되고 대소 문자를 구분하는 프롬프트 목록입니다. 이 매개 변수를 지정하지 않으면 프로젝트에서 처음으로 액세스를 요청할 때만 사용자에게 메시지가 표시됩니다. 자세한 내용은 재동의 요청 을 참조하십시오.

Python에서는 flow.authorization_url 메서드를 호출 할 때 prompt 를 키워드 인수로 지정하여 prompt 매개 변수를 설정합니다.

authorization_url, state = flow.authorization_url(
      access_type='offline',
      prompt='consent',
      include_granted_scopes='true')

가능한 값은 다음과 같습니다.

none 인증 또는 동의 화면을 표시하지 마십시오. 다른 값과 함께 지정하면 안됩니다.
consent 사용자에게 동의를 요청합니다.
select_account 사용자에게 계정을 선택하라는 메시지를 표시합니다.

루비

애플리케이션에서 클라이언트 객체를 구성하기 위해 생성 한 client_secrets.json 파일을 사용합니다. 클라이언트 개체를 구성 할 때 OAuth 2.0 서버의 응답을 처리 할 애플리케이션의 인증 엔드 포인트에 대한 URL과 함께 애플리케이션이 액세스해야하는 범위를 지정합니다.

예를 들어 다음 코드는 사용자의 Google 드라이브에 대한 읽기 전용 오프라인 액세스를 요청합니다.

require 'google/apis/drive_v2'
require 'google/api_client/client_secrets'

client_secrets = Google::APIClient::ClientSecrets.load
auth_client = client_secrets.to_authorization
auth_client.update!(
  :scope => 'https://www.googleapis.com/auth/drive.metadata.readonly',
  :redirect_uri => 'http://www.example.com/oauth2callback',
  :additional_parameters => {
    "access_type" => "offline",         # offline access
    "include_granted_scopes" => "true"  # incremental auth
  }
)

애플리케이션은 클라이언트 개체를 사용하여 인증 요청 URL 생성 및 HTTP 요청에 액세스 토큰 적용과 같은 OAuth 2.0 작업을 수행합니다.

HTTP / REST

Google의 OAuth 2.0 엔드 포인트는 https://accounts.google.com/o/oauth2/v2/auth 있습니다. 이 끝점은 HTTPS를 통해서만 액세스 할 수 있습니다. 일반 HTTP 연결은 거부됩니다.

Google 인증 서버는 웹 서버 애플리케이션에 대해 다음 쿼리 문자열 매개 변수를 지원합니다.

매개 변수
client_id 필수

애플리케이션의 클라이언트 ID입니다. 이 값은 API Console Credentials page에서 찾을 수 있습니다.

redirect_uri 필수

사용자가 인증 흐름을 완료 한 후 API 서버가 사용자를 리디렉션하는 위치를 결정합니다. 이 값은 클라이언트의 API Console Credentials page에서 구성한 OAuth 2.0 클라이언트에 대해 승인 된 리디렉션 URI 중 하나와 정확히 일치해야합니다. 이 값이 제공된 client_id 대해 승인 된 리디렉션 URI와 일치하지 않으면 redirect_uri_mismatch 오류가 발생합니다.

http 또는 https 체계, 대소 문자 및 후행 슬래시 ( ' / ')가 모두 일치해야합니다.

response_type 필수

Google OAuth 2.0 엔드 포인트가 인증 코드를 반환하는지 여부를 결정합니다.

매개 변수 값을 웹 서버 애플리케이션 용 code 로 설정하십시오.

scope 필수

애플리케이션이 사용자를 대신하여 액세스 할 수있는 리소스를 식별하는 공백으로 구분 된 범위 목록입니다. 이 값은 Google이 사용자에게 표시하는 동의 화면을 알려줍니다.

범위를 사용하면 애플리케이션이 필요한 리소스에 대한 액세스 만 요청할 수 있으며 사용자는 애플리케이션에 부여하는 액세스 양을 제어 할 수 있습니다. 따라서 요청 된 범위의 수와 사용자 동의를 얻을 가능성 사이에는 반비례 관계가 있습니다.

가능한 경우 애플리케이션에서 컨텍스트에서 권한 부여 범위에 대한 액세스를 요청하는 것이 좋습니다. 증분 권한 부여 를 통해 컨텍스트에서 사용자 데이터에 대한 액세스를 요청하면 사용자가 애플리케이션에서 요청하는 액세스가 필요한 이유를보다 쉽게 ​​이해할 수 있습니다.

access_type 추천

사용자가 브라우저에 없을 때 애플리케이션이 액세스 토큰을 새로 고칠 수 있는지 여부를 나타냅니다. 유효한 매개 변수 값은 기본값 인 onlineoffline 입니다.

사용자가 브라우저에 없을 때 애플리케이션에서 액세스 토큰을 새로 고쳐야하는 경우 값을 offline 설정하십시오. 이 문서의 뒷부분에서 설명하는 액세스 토큰을 새로 고치는 방법입니다. 이 값은 애플리케이션이 처음으로 인증 코드를 토큰으로 교환 할 때 새로 고침 토큰 액세스 토큰을 반환하도록 Google 인증 서버에 지시합니다.

state 추천

애플리케이션이 권한 요청과 권한 서버의 응답 사이의 상태를 유지하기 위해 사용하는 문자열 값을 지정합니다. 서버는 사용자가 애플리케이션의 액세스 요청에 동의하거나 거부 한 후 redirect_uri 의 URL 쿼리 구성 요소 ( ? )에 name=value 쌍으로 보내는 정확한 값을 반환합니다.

이 매개 변수는 사용자를 애플리케이션의 올바른 리소스로 안내하고, nonce를 전송하고, 교차 사이트 요청 위조를 완화하는 등 여러 목적으로 사용할 수 있습니다. redirect_uri 를 추측 할 수 있으므로 state 값을 사용하면 들어오는 연결이 인증 요청의 결과라는 확신을 높일 수 있습니다. 임의의 문자열을 생성하거나 쿠키의 해시 또는 클라이언트의 상태를 캡처하는 다른 값을 인코딩하는 경우 요청과 응답이 동일한 브라우저에서 시작되었는지 추가로 확인하여 교차 사이트와 같은 공격에 대한 보호를 제공하기 위해 응답을 검증 할 수 있습니다. 위조 요청. state 토큰을 만들고 확인하는 방법에 대한 예제는 OpenID Connect 설명서를 참조하십시오.

include_granted_scopes 선택 과목

애플리케이션이 증분 인증을 사용하여 컨텍스트의 추가 범위에 대한 액세스를 요청할 수 있도록합니다. 이 매개 변수의 값을 true 설정하고 권한 부여 요청이 부여 된 경우 새 액세스 토큰은 사용자가 이전에 애플리케이션 액세스 권한을 부여한 모든 범위도 포함합니다. 예시는 증분 인증 섹션을 참조하세요.

login_hint 선택 과목

애플리케이션이 인증하려는 사용자를 알고있는 경우이 매개 변수를 사용하여 Google 인증 서버에 힌트를 제공 할 수 있습니다. 서버는 힌트를 사용하여 로그인 양식의 이메일 필드를 미리 채우거나 적절한 다중 로그인 세션을 선택하여 로그인 흐름을 단순화합니다.

매개 변수 값을 사용자의 Google ID와 동일한 이메일 주소 또는 sub 식별자로 설정합니다.

prompt 선택 과목

사용자에게 표시 할 공백으로 구분되고 대소 문자를 구분하는 프롬프트 목록입니다. 이 매개 변수를 지정하지 않으면 프로젝트에서 처음 액세스를 요청할 때만 사용자에게 메시지가 표시됩니다. 자세한 내용은 재동의 요청 을 참조하십시오.

가능한 값은 다음과 같습니다.

none 인증 또는 동의 화면을 표시하지 마십시오. 다른 값과 함께 지정하면 안됩니다.
consent 사용자에게 동의를 요청합니다.
select_account 사용자에게 계정을 선택하라는 메시지를 표시합니다.

2 단계 : Google의 OAuth 2.0 서버로 리디렉션

사용자를 Google의 OAuth 2.0 서버로 리디렉션하여 인증 및 승인 프로세스를 시작합니다. 일반적으로 이는 애플리케이션이 사용자의 데이터에 처음 액세스해야 할 때 발생합니다. 증분 인증 의 경우이 단계는 애플리케이션이 아직 액세스 권한이없는 추가 리소스에 처음 액세스해야하는 경우에도 발생합니다.

PHP

  1. Google의 OAuth 2.0 서버에서 액세스를 요청하는 URL 생성 :
    $auth_url = $client->createAuthUrl();
  2. 사용자를 $auth_url :
    header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));
    으로 리디렉션합니다.

파이썬

이 예제는 Flask 웹 애플리케이션 프레임 워크를 사용하여 사용자를 인증 URL로 리디렉션하는 방법을 보여줍니다.

return flask.redirect(authorization_url)

루비

  1. Google의 OAuth 2.0 서버에서 액세스를 요청하는 URL 생성 :
    auth_uri = auth_client.authorization_uri.to_s
  2. 사용자를 auth_uri 리디렉션합니다.

HTTP / REST

Google의 인증 서버로의 샘플 리디렉션

아래에는 가독성을 위해 줄 바꿈과 공백이 포함 된 예제 URL이 나와 있습니다.

https://accounts.google.com/o/oauth2/v2/auth?
 scope=https%3A//www.googleapis.com/auth/drive.metadata.readonly&
 access_type=offline&
 include_granted_scopes=true&
 response_type=code&
 state=state_parameter_passthrough_value&
 redirect_uri=https%3A//oauth2.example.com/code&
 client_id=client_id

요청 URL을 만든 후 사용자를 리디렉션합니다.

Google의 OAuth 2.0 서버는 사용자를 인증하고 애플리케이션이 요청 된 범위에 액세스 할 수 있도록 사용자로부터 동의를 얻습니다. 응답은 지정한 리디렉션 URL을 사용하여 애플리케이션으로 다시 전송됩니다.

3 단계 : Google에서 사용자에게 동의를 요청합니다.

이 단계에서 사용자는 애플리케이션에 요청 된 액세스 권한을 부여할지 여부를 결정합니다. 이 단계에서 Google은 사용자의 인증 자격 증명으로 액세스 권한을 요청하는 애플리케이션 및 Google API 서비스의 이름과 부여 할 액세스 범위 요약을 보여주는 동의 창을 표시합니다. 그런 다음 사용자는 애플리케이션에서 요청한 하나 이상의 범위에 대한 액세스 권한을 부여하거나 요청을 거부하는 데 동의 할 수 있습니다.

애플리케이션은 액세스 권한이 부여되었는지 여부를 나타내는 Google의 OAuth 2.0 서버의 응답을 기다리므로이 단계에서 아무것도 할 필요가 없습니다. 그 응답은 다음 단계에서 설명됩니다.

4 단계 : OAuth 2.0 서버 응답 처리

OAuth 2.0 서버는 요청에 지정된 URL을 사용하여 애플리케이션의 액세스 요청에 응답합니다.

사용자가 액세스 요청을 승인하면 응답에 인증 코드가 포함됩니다. 사용자가 요청을 승인하지 않으면 응답에 오류 메시지가 포함됩니다. 웹 서버로 반환되는 인증 코드 또는 오류 메시지는 아래와 같이 쿼리 문자열에 나타납니다.

오류 응답 :

https://oauth2.example.com/auth?error=access_denied

승인 코드 응답 :

https://oauth2.example.com/auth?code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7

샘플 OAuth 2.0 서버 응답

Google 드라이브의 파일에 대한 메타 데이터를보기 위해 읽기 전용 액세스를 요청하는 다음 샘플 URL을 클릭하여이 흐름을 테스트 할 수 있습니다.

https://accounts.google.com/o/oauth2/v2/auth?
 scope=https%3A//www.googleapis.com/auth/drive.metadata.readonly&
 access_type=offline&
 include_granted_scopes=true&
 response_type=code&
 state=state_parameter_passthrough_value&
 redirect_uri=https%3A//oauth2.example.com/code&
 client_id=client_id

OAuth 2.0 흐름을 완료 한 후 http://localhost/oauth2callback 으로 리디렉션되어야합니다. 로컬 컴퓨터가 해당 주소에서 파일을 제공하지 않는 한 404 NOT FOUND 오류가 발생할 수 있습니다. 다음 단계에서는 사용자가 애플리케이션으로 다시 리디렉션 될 때 URI에 반환되는 정보에 대한 자세한 정보를 제공합니다.

5 단계 : 새로 고침 및 액세스 토큰에 대한 인증 코드 교환

웹 서버는 인증 코드를받은 후 인증 코드를 액세스 토큰으로 교환 할 수 있습니다.

PHP

액세스 토큰에 대한 인증 코드를 교환하려면 authenticate 방법을 사용하십시오.

$client->authenticate($_GET['code']);

getAccessToken 메소드를 사용하여 액세스 토큰을 검색 할 수 있습니다.

$access_token = $client->getAccessToken();

파이썬

콜백 페이지에서 google-auth 라이브러리를 사용하여 인증 서버 응답을 확인합니다. 그런 다음 flow.fetch_token 메서드를 사용하여 해당 응답의 인증 코드를 액세스 토큰으로 교환합니다.

state = flask.session['state']
flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
    'client_secret.json',
    scopes=['https://www.googleapis.com/auth/drive.metadata.readonly'],
    state=state)
flow.redirect_uri = flask.url_for('oauth2callback', _external=True)

authorization_response = flask.request.url
flow.fetch_token(authorization_response=authorization_response)

# Store the credentials in the session.
# ACTION ITEM for developers:
#     Store user's access and refresh tokens in your data store if
#     incorporating this code into your real app.
credentials = flow.credentials
flask.session['credentials'] = {
    'token': credentials.token,
    'refresh_token': credentials.refresh_token,
    'token_uri': credentials.token_uri,
    'client_id': credentials.client_id,
    'client_secret': credentials.client_secret,
    'scopes': credentials.scopes}

루비

액세스 토큰에 대한 인증 코드를 교환하려면 fetch_access_token! 방법:

auth_client.code = auth_code
auth_client.fetch_access_token!

HTTP / REST

액세스 토큰에 대한 인증 코드를 교환하려면 https://oauth2.googleapis.com/token 엔드 포인트를 호출하고 다음 매개 변수를 설정 https://oauth2.googleapis.com/token .

필드
client_id API Console Credentials page에서 얻은 클라이언트 ID입니다.
client_secret API Console Credentials page에서 얻은 클라이언트 암호입니다.
code 초기 요청에서 반환 된 인증 코드입니다.
grant_type OAuth 2.0 사양에 정의 된대로이 필드의 값은 authorization_code 로 설정해야합니다.
redirect_uri 주어진 client_id 에 대해 API Console Credentials page에 프로젝트에 대해 나열된 리디렉션 URI 중 하나입니다.

다음 스 니펫은 샘플 요청을 보여줍니다.

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

Google은 단기 액세스 토큰과 새로 고침 토큰이 포함 된 JSON 객체를 반환하여이 요청에 응답합니다. 새로 고침 토큰은 애플리케이션 이 Google 인증 서버대한 초기 요청 에서 access_type 매개 변수를 offline 으로 설정 한 경우에만 반환됩니다.

응답에는 다음 필드가 포함됩니다.

필드
access_token 애플리케이션이 Google API 요청을 승인하기 위해 보내는 토큰입니다.
expires_in 액세스 토큰의 남은 수명 (초)입니다.
refresh_token 새 액세스 토큰을 얻는 데 사용할 수있는 토큰입니다. 새로 고침 토큰은 사용자가 액세스를 취소 할 때까지 유효합니다. 다시 말하지만이 필드는 Google 인증 서버에 대한 초기 요청에서 access_type 매개 변수를 offline 으로 설정 한 경우에만이 응답에 표시됩니다.
scope 공백으로 구분되고 대소 문자를 구분하는 문자열 목록으로 표현되는 access_token 의해 부여 된 액세스 범위입니다.
token_type 반환 된 토큰 유형입니다. 이때이 필드의 값은 항상 Bearer 설정됩니다.

The following snippet shows a sample response:

{
  "access_token": "1/fFAGRNJru1FTz70BzhT3Zg",
  "expires_in": 3920,
  "token_type": "Bearer",
  "scope": "https://www.googleapis.com/auth/drive.metadata.readonly",
  "refresh_token": "1//xEoDL4iW3cxlI7yDbSRFYNG01kVKM2C-259HOF2aQbI"
}

Calling Google APIs

PHP

Use the access token to call Google APIs by completing the following steps:

  1. If you need to apply an access token to a new Google_Client object—for example, if you stored the access token in a user session—use the setAccessToken method:
    $client->setAccessToken($access_token);
  2. Build a service object for the API that you want to call. You build a service object by providing an authorized Google_Client object to the constructor for the API you want to call. For example, to call the Drive API:
    $drive = new Google_Service_Drive($client);
  3. Make requests to the API service using the interface provided by the service object . For example, to list the files in the authenticated user's Google Drive:
    $files = $drive->files->listFiles(array())->getItems();

Python

After obtaining an access token, your application can use that token to authorize API requests on behalf of a given user account or service account. Use the user-specific authorization credentials to build a service object for the API that you want to call, and then use that object to make authorized API requests.

  1. Build a service object for the API that you want to call. You build a service object by calling the googleapiclient.discovery library's build method with the name and version of the API and the user credentials: For example, to call version 2 of the Drive API:
    from googleapiclient.discovery import build
    
    drive = build('drive', 'v2', credentials=credentials)
  2. Make requests to the API service using the interface provided by the service object . For example, to list the files in the authenticated user's Google Drive:
    files = drive.files().list().execute()

Ruby

Use the auth_client object to call Google APIs by completing the following steps:

  1. Build a service object for the API that you want to call. For example, to call version 2 of the Drive API:
    drive = Google::Apis::DriveV2::DriveService.new
  2. Set the credentials on the service:
    drive.authorization = auth_client
  3. Make requests to the API service using the interface provided by the service object . For example, to list the files in the authenticated user's Google Drive:
    files = drive.list_files

Alternately, authorization can be provided on a per-method basis by supplying the options parameter to a method:

files = drive.list_files(options: { authorization: auth_client })

HTTP/REST

After your application obtains an access token, you can use the token to make calls to a Google API on behalf of a given user account if the scope(s) of access required by the API have been granted. To do this, include the access token in a request to the API by including either an access_token query parameter or an Authorization HTTP header Bearer value. When possible, the HTTP header is preferable, because query strings tend to be visible in server logs. In most cases you can use a client library to set up your calls to Google APIs (for example, when calling the Drive Files API ).

You can try out all the Google APIs and view their scopes at the OAuth 2.0 Playground .

HTTP GET examples

A call to the drive.files endpoint (the Drive Files API) using the Authorization: Bearer HTTP header might look like the following. Note that you need to specify your own access token:

GET /drive/v2/files HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer access_token

Here is a call to the same API for the authenticated user using the access_token query string parameter:

GET https://www.googleapis.com/drive/v2/files?access_token=access_token

curl examples

You can test these commands with the curl command-line application. Here's an example that uses the HTTP header option (preferred):

curl -H "Authorization: Bearer access_token" https://www.googleapis.com/drive/v2/files

Or, alternatively, the query string parameter option:

curl https://www.googleapis.com/drive/v2/files?access_token=access_token

Complete example

The following example prints a JSON-formatted list of files in a user's Google Drive after the user authenticates and gives consent for the application to access the user's Drive metadata.

PHP

To run this example:

  1. In the API Console, add the URL of the local machine to the list of redirect URLs. For example, add http://localhost:8080 .
  2. Create a new directory and change to it. For example:
    mkdir ~/php-oauth2-example
    cd ~/php-oauth2-example
  3. Install the Google API Client Library for PHP using Composer :
    composer require google/apiclient:^2.0
  4. Create the files index.php and oauth2callback.php with the content below.
  5. Run the example with a web server configured to serve PHP. If you use PHP 5.4 or newer, you can use PHP's built-in test web server:
    php -S localhost:8080 ~/php-oauth2-example

index.php

<?php
require_once __DIR__.'/vendor/autoload.php';

session_start();

$client = new Google_Client();
$client->setAuthConfig('client_secrets.json');
$client->addScope(Google_Service_Drive::DRIVE_METADATA_READONLY);

if (isset($_SESSION['access_token']) && $_SESSION['access_token']) {
  $client->setAccessToken($_SESSION['access_token']);
  $drive = new Google_Service_Drive($client);
  $files = $drive->files->listFiles(array())->getItems();
  echo json_encode($files);
} else {
  $redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback.php';
  header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}

oauth2callback.php

<?php
require_once __DIR__.'/vendor/autoload.php';

session_start();

$client = new Google_Client();
$client->setAuthConfigFile('client_secrets.json');
$client->setRedirectUri('http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback.php');
$client->addScope(Google_Service_Drive::DRIVE_METADATA_READONLY);

if (! isset($_GET['code'])) {
  $auth_url = $client->createAuthUrl();
  header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));
} else {
  $client->authenticate($_GET['code']);
  $_SESSION['access_token'] = $client->getAccessToken();
  $redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . '/';
  header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}

Python

This example uses the Flask framework. It runs a web application at http://localhost:8080 that lets you test the OAuth 2.0 flow. If you go to that URL, you should see four links:

  • Test an API request: This link points to a page that tries to execute a sample API request. If necessary, it starts the authorization flow. If successful, the page displays the API response.
  • Test the auth flow directly: This link points to a page that tries to send the user through the authorization flow . The app requests permission to submit authorized API requests on the user's behalf.
  • Revoke current credentials: This link points to a page that revokes permissions that the user has already granted to the application.
  • Clear Flask session credentials: This link clears authorization credentials that are stored in the Flask session. This lets you see what would happen if a user who had already granted permission to your app tried to execute an API request in a new session. It also lets you see the API response your app would get if a user had revoked permissions granted to your app, and your app still tried to authorize a request with a revoked access token.
# -*- coding: utf-8 -*-

import os
import flask
import requests

import google.oauth2.credentials
import google_auth_oauthlib.flow
import googleapiclient.discovery

# This variable specifies the name of a file that contains the OAuth 2.0
# information for this application, including its client_id and client_secret.
CLIENT_SECRETS_FILE = "client_secret.json"

# This OAuth 2.0 access scope allows for full read/write access to the
# authenticated user's account and requires requests to use an SSL connection.
SCOPES = ['https://www.googleapis.com/auth/drive.metadata.readonly']
API_SERVICE_NAME = 'drive'
API_VERSION = 'v2'

app = flask.Flask(__name__)
# Note: A secret key is included in the sample so that it works.
# If you use this code in your application, replace this with a truly secret
# key. See https://flask.palletsprojects.com/quickstart/#sessions.
app.secret_key = 'REPLACE ME - this value is here as a placeholder.'


@app.route('/')
def index():
  return print_index_table()


@app.route('/test')
def test_api_request():
  if 'credentials' not in flask.session:
    return flask.redirect('authorize')

  # Load credentials from the session.
  credentials = google.oauth2.credentials.Credentials(
      **flask.session['credentials'])

  drive = googleapiclient.discovery.build(
      API_SERVICE_NAME, API_VERSION, credentials=credentials)

  files = drive.files().list().execute()

  # Save credentials back to session in case access token was refreshed.
  # ACTION ITEM: In a production app, you likely want to save these
  #              credentials in a persistent database instead.
  flask.session['credentials'] = credentials_to_dict(credentials)

  return flask.jsonify(**files)


@app.route('/authorize')
def authorize():
  # Create flow instance to manage the OAuth 2.0 Authorization Grant Flow steps.
  flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
      CLIENT_SECRETS_FILE, scopes=SCOPES)

  # The URI created here must exactly match one of the authorized redirect URIs
  # for the OAuth 2.0 client, which you configured in the API Console. If this
  # value doesn't match an authorized URI, you will get a 'redirect_uri_mismatch'
  # error.
  flow.redirect_uri = flask.url_for('oauth2callback', _external=True)

  authorization_url, state = flow.authorization_url(
      # Enable offline access so that you can refresh an access token without
      # re-prompting the user for permission. Recommended for web server apps.
      access_type='offline',
      # Enable incremental authorization. Recommended as a best practice.
      include_granted_scopes='true')

  # Store the state so the callback can verify the auth server response.
  flask.session['state'] = state

  return flask.redirect(authorization_url)


@app.route('/oauth2callback')
def oauth2callback():
  # Specify the state when creating the flow in the callback so that it can
  # verified in the authorization server response.
  state = flask.session['state']

  flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
      CLIENT_SECRETS_FILE, scopes=SCOPES, state=state)
  flow.redirect_uri = flask.url_for('oauth2callback', _external=True)

  # Use the authorization server's response to fetch the OAuth 2.0 tokens.
  authorization_response = flask.request.url
  flow.fetch_token(authorization_response=authorization_response)

  # Store credentials in the session.
  # ACTION ITEM: In a production app, you likely want to save these
  #              credentials in a persistent database instead.
  credentials = flow.credentials
  flask.session['credentials'] = credentials_to_dict(credentials)

  return flask.redirect(flask.url_for('test_api_request'))


@app.route('/revoke')
def revoke():
  if 'credentials' not in flask.session:
    return ('You need to <a href="/authorize">authorize</a> before ' +
            'testing the code to revoke credentials.')

  credentials = google.oauth2.credentials.Credentials(
    **flask.session['credentials'])

  revoke = requests.post('https://oauth2.googleapis.com/revoke',
      params={'token': credentials.token},
      headers = {'content-type': 'application/x-www-form-urlencoded'})

  status_code = getattr(revoke, 'status_code')
  if status_code == 200:
    return('Credentials successfully revoked.' + print_index_table())
  else:
    return('An error occurred.' + print_index_table())


@app.route('/clear')
def clear_credentials():
  if 'credentials' in flask.session:
    del flask.session['credentials']
  return ('Credentials have been cleared.<br><br>' +
          print_index_table())


def credentials_to_dict(credentials):
  return {'token': credentials.token,
          'refresh_token': credentials.refresh_token,
          'token_uri': credentials.token_uri,
          'client_id': credentials.client_id,
          'client_secret': credentials.client_secret,
          'scopes': credentials.scopes}

def print_index_table():
  return ('<table>' +
          '<tr><td><a href="/test">Test an API request</a></td>' +
          '<td>Submit an API request and see a formatted JSON response. ' +
          '    Go through the authorization flow if there are no stored ' +
          '    credentials for the user.</td></tr>' +
          '<tr><td><a href="/authorize">Test the auth flow directly</a></td>' +
          '<td>Go directly to the authorization flow. If there are stored ' +
          '    credentials, you still might not be prompted to reauthorize ' +
          '    the application.</td></tr>' +
          '<tr><td><a href="/revoke">Revoke current credentials</a></td>' +
          '<td>Revoke the access token associated with the current user ' +
          '    session. After revoking credentials, if you go to the test ' +
          '    page, you should see an <code>invalid_grant</code> error.' +
          '</td></tr>' +
          '<tr><td><a href="/clear">Clear Flask session credentials</a></td>' +
          '<td>Clear the access token currently stored in the user session. ' +
          '    After clearing the token, if you <a href="/test">test the ' +
          '    API request</a> again, you should go back to the auth flow.' +
          '</td></tr></table>')


if __name__ == '__main__':
  # When running locally, disable OAuthlib's HTTPs verification.
  # ACTION ITEM for developers:
  #     When running in production *do not* leave this option enabled.
  os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1'

  # Specify a hostname and port that are set as a valid redirect URI
  # for your API project in the Google API Console.
  app.run('localhost', 8080, debug=True)

Ruby

This example uses the Sinatra framework.

require 'google/apis/drive_v2'
require 'google/api_client/client_secrets'
require 'json'
require 'sinatra'

enable :sessions
set :session_secret, 'setme'

get '/' do
  unless session.has_key?(:credentials)
    redirect to('/oauth2callback')
  end
  client_opts = JSON.parse(session[:credentials])
  auth_client = Signet::OAuth2::Client.new(client_opts)
  drive = Google::Apis::DriveV2::DriveService.new
  files = drive.list_files(options: { authorization: auth_client })
  "<pre>#{JSON.pretty_generate(files.to_h)}</pre>"
end

get '/oauth2callback' do
  client_secrets = Google::APIClient::ClientSecrets.load
  auth_client = client_secrets.to_authorization
  auth_client.update!(
    :scope => 'https://www.googleapis.com/auth/drive.metadata.readonly',
    :redirect_uri => url('/oauth2callback'))
  if request['code'] == nil
    auth_uri = auth_client.authorization_uri.to_s
    redirect to(auth_uri)
  else
    auth_client.code = request['code']
    auth_client.fetch_access_token!
    auth_client.client_secret = nil
    session[:credentials] = auth_client.to_json
    redirect to('/')
  end
end

HTTP/REST

This Python example uses the Flask framework and the Requests library to demonstrate the OAuth 2.0 web flow. We recommend using the Google API Client Library for Python for this flow. (The example in the Python tab does use the client library.)

import json

import flask
import requests


app = flask.Flask(__name__)

CLIENT_ID = '123456789.apps.googleusercontent.com'
CLIENT_SECRET = 'abc123'  # Read from a file or environmental variable in a real app
SCOPE = 'https://www.googleapis.com/auth/drive.metadata.readonly'
REDIRECT_URI = 'http://example.com/oauth2callback'


@app.route('/')
def index():
  if 'credentials' not in flask.session:
    return flask.redirect(flask.url_for('oauth2callback'))
  credentials = json.loads(flask.session['credentials'])
  if credentials['expires_in'] <= 0:
    return flask.redirect(flask.url_for('oauth2callback'))
  else:
    headers = {'Authorization': 'Bearer {}'.format(credentials['access_token'])}
    req_uri = 'https://www.googleapis.com/drive/v2/files'
    r = requests.get(req_uri, headers=headers)
    return r.text


@app.route('/oauth2callback')
def oauth2callback():
  if 'code' not in flask.request.args:
    auth_uri = ('https://accounts.google.com/o/oauth2/v2/auth?response_type=code'
                '&client_id={}&redirect_uri={}&scope={}').format(CLIENT_ID, REDIRECT_URI, SCOPE)
    return flask.redirect(auth_uri)
  else:
    auth_code = flask.request.args.get('code')
    data = {'code': auth_code,
            'client_id': CLIENT_ID,
            'client_secret': CLIENT_SECRET,
            'redirect_uri': REDIRECT_URI,
            'grant_type': 'authorization_code'}
    r = requests.post('https://oauth2.googleapis.com/token', data=data)
    flask.session['credentials'] = r.text
    return flask.redirect(flask.url_for('index'))


if __name__ == '__main__':
  import uuid
  app.secret_key = str(uuid.uuid4())
  app.debug = False
  app.run()

Redirect URI validation rules

Google applies the following validation rules to redirect URIs in order to help developers keep their applications secure. Your redirect URIs must adhere to these rules. See RFC 3986 section 3 for the definition of domain, host, path, query, scheme and userinfo, mentioned below.

Validation rules
Scheme

URIs must use the HTTPS scheme, not plain HTTP.

Host

Hosts cannot be raw IP addresses. Localhost IP addresses are exempted from this rule.

Domain
  • Host TLDs ( Top Level Domains ) must belong to the public suffix list .
  • Host domains cannot be “googleusercontent.com” .
  • URIs cannot contain URL shortener domains (eg goo.gl ) unless the app owns the domain. Furthermore, if an app that owns a shortener domain chooses to redirect to that domain, that redirect URI must either contain “/google-callback/” in its path or end with “/google-callback” .
  • Userinfo

    Redirect URIs cannot contain the userinfo subcomponent.

    Path

    Redirect URIs cannot contain a path traversal (also called directory backtracking), which is represented by an “/..” or “\..” or their URL encoding.

    Query

    Redirect URIs cannot contain open redirects .

    Characters URIs cannot contain certain characters including:
    • Wildcard characters ( '*' )
    • Non-printable ASCII characters
    • Invalid percent encodings (any percent encoding that does not follow URL-encoding form of a percent sign followed by two hexadecimal digits)
    • Null characters (an encoded NULL character, eg, %00 , %C0%80 )

    Incremental authorization

    In the OAuth 2.0 protocol, your app requests authorization to access resources, which are identified by scopes. It is considered a best user-experience practice to request authorization for resources at the time you need them. To enable that practice, Google's authorization server supports incremental authorization. This feature lets you request scopes as they are needed and, if the user grants permission for the new scope, returns an authorization code that may be exchanged for a token containing all scopes the user has granted the project.

    For example, an app that lets people sample music tracks and create mixes might need very few resources at sign-in time, perhaps nothing more than the name of the person signing in. However, saving a completed mix would require access to their Google Drive. Most people would find it natural if they only were asked for access to their Google Drive at the time the app actually needed it.

    In this case, at sign-in time the app might request the openid and profile scopes to perform basic sign-in, and then later request the https://www.googleapis.com/auth/drive.file scope at the time of the first request to save a mix.

    To implement incremental authorization, you complete the normal flow for requesting an access token but make sure that the authorization request includes previously granted scopes. This approach allows your app to avoid having to manage multiple access tokens.

    The following rules apply to an access token obtained from an incremental authorization:

    • The token can be used to access resources corresponding to any of the scopes rolled into the new, combined authorization.
    • When you use the refresh token for the combined authorization to obtain an access token, the access token represents the combined authorization and can be used for any of the scope values included in the response.
    • The combined authorization includes all scopes that the user granted to the API project even if the grants were requested from different clients. For example, if a user granted access to one scope using an application's desktop client and then granted another scope to the same application via a mobile client, the combined authorization would include both scopes.
    • If you revoke a token that represents a combined authorization, access to all of that authorization's scopes on behalf of the associated user are revoked simultaneously.

    The language-specific code samples in Step 1: Set authorization parameters and the sample HTTP/REST redirect URL in Step 2: Redirect to Google's OAuth 2.0 server all use incremental authorization. The code samples below also show the code that you need to add to use incremental authorization.

    PHP

    $client->setIncludeGrantedScopes(true);

    Python

    In Python, set the include_granted_scopes keyword argument to true to ensure that an authorization request includes previously granted scopes. It is very possible that include_granted_scopes will not be the only keyword argument that you set, as shown in the example below.

    authorization_url, state = flow.authorization_url(
        # Enable offline access so that you can refresh an access token without
        # re-prompting the user for permission. Recommended for web server apps.
        access_type='offline',
        # Enable incremental authorization. Recommended as a best practice.
        include_granted_scopes='true')

    Ruby

    auth_client.update!(
      :additional_parameters => {"include_granted_scopes" => "true"}
    )

    HTTP/REST

    GET https://accounts.google.com/o/oauth2/v2/auth?
      client_id=your_client_id&
      response_type=code&
      state=state_parameter_passthrough_value&
      scope=https%3A//www.googleapis.com/auth/drive.file&
      redirect_uri=https%3A//oauth2.example.com/code&
      prompt=consent&
      include_granted_scopes=true

    Refreshing an access token (offline access)

    Access tokens periodically expire and become invalid credentials for a related API request. You can refresh an access token without prompting the user for permission (including when the user is not present) if you requested offline access to the scopes associated with the token.

    • If you use a Google API Client Library, the client object refreshes the access token as needed as long as you configure that object for offline access.
    • If you are not using a client library, you need to set the access_type HTTP query parameter to offline when redirecting the user to Google's OAuth 2.0 server . In that case, Google's authorization server returns a refresh token when you exchange an authorization code for an access token. Then, if the access token expires (or at any other time), you can use a refresh token to obtain a new access token.

    Requesting offline access is a requirement for any application that needs to access a Google API when the user is not present. For example, an app that performs backup services or executes actions at predetermined times needs to be able to refresh its access token when the user is not present. The default style of access is called online .

    Server-side web applications, installed applications, and devices all obtain refresh tokens during the authorization process. Refresh tokens are not typically used in client-side (JavaScript) web applications.

    PHP

    If your application needs offline access to a Google API, set the API client's access type to offline :

    $client->setAccessType("offline");

    After a user grants offline access to the requested scopes, you can continue to use the API client to access Google APIs on the user's behalf when the user is offline. The client object will refresh the access token as needed.

    Python

    In Python, set the access_type keyword argument to offline to ensure that you will be able to refresh the access token without having to re-prompt the user for permission. It is very possible that access_type will not be the only keyword argument that you set, as shown in the example below.

    authorization_url, state = flow.authorization_url(
        # Enable offline access so that you can refresh an access token without
        # re-prompting the user for permission. Recommended for web server apps.
        access_type='offline',
        # Enable incremental authorization. Recommended as a best practice.
        include_granted_scopes='true')

    After a user grants offline access to the requested scopes, you can continue to use the API client to access Google APIs on the user's behalf when the user is offline. The client object will refresh the access token as needed.

    Ruby

    If your application needs offline access to a Google API, set the API client's access type to offline :

    auth_client.update!(
      :additional_parameters => {"access_type" => "offline"}
    )

    After a user grants offline access to the requested scopes, you can continue to use the API client to access Google APIs on the user's behalf when the user is offline. The client object will refresh the access token as needed.

    HTTP/REST

    To refresh an access token, your application sends an HTTPS POST request to Google's authorization server ( https://oauth2.googleapis.com/token ) that includes the following parameters:

    필드
    client_id The client ID obtained from the API Console.
    client_secret The client secret obtained from the API Console.
    grant_type As defined in the OAuth 2.0 specification , this field's value must be set to refresh_token .
    refresh_token The refresh token returned from the authorization code exchange.

    The following snippet shows a sample request:

    POST /token HTTP/1.1
    Host: oauth2.googleapis.com
    Content-Type: application/x-www-form-urlencoded
    
    client_id=your_client_id&
    client_secret=your_client_secret&
    refresh_token=refresh_token&
    grant_type=refresh_token

    As long as the user has not revoked the access granted to the application, the token server returns a JSON object that contains a new access token. The following snippet shows a sample response:

    {
      "access_token": "1/fFAGRNJru1FTz70BzhT3Zg",
      "expires_in": 3920,
      "scope": "https://www.googleapis.com/auth/drive.metadata.readonly",
      "token_type": "Bearer"
    }

    Note that there are limits on the number of refresh tokens that will be issued; one limit per client/user combination, and another per user across all clients. You should save refresh tokens in long-term storage and continue to use them as long as they remain valid. If your application requests too many refresh tokens, it may run into these limits, in which case older refresh tokens will stop working.

    Revoking a token

    In some cases a user may wish to revoke access given to an application. A user can revoke access by visiting Account Settings . See the Remove site or app access section of the Third-party sites & apps with access to your account support document for more information.

    It is also possible for an application to programmatically revoke the access given to it. Programmatic revocation is important in instances where a user unsubscribes, removes an application, or the API resources required by an app have significantly changed. In other words, part of the removal process can include an API request to ensure the permissions previously granted to the application are removed.

    PHP

    To programmatically revoke a token, call revokeToken() :

    $client->revokeToken();

    Python

    To programmatically revoke a token, make a request to https://oauth2.googleapis.com/revoke that includes the token as a parameter and sets the Content-Type header:

    requests.post('https://oauth2.googleapis.com/revoke',
        params={'token': credentials.token},
        headers = {'content-type': 'application/x-www-form-urlencoded'})

    Ruby

    To programmatically revoke a token, make an HTTP request to the oauth2.revoke endpoint:

    uri = URI('https://oauth2.googleapis.com/revoke')
    response = Net::HTTP.post_form(uri, 'token' => auth_client.access_token)
    

    The token can be an access token or a refresh token. If the token is an access token and it has a corresponding refresh token, the refresh token will also be revoked.

    If the revocation is successfully processed, then the status code of the response is 200 . For error conditions, a status code 400 is returned along with an error code.

    HTTP/REST

    To programmatically revoke a token, your application makes a request to https://oauth2.googleapis.com/revoke and includes the token as a parameter:

    curl -d -X -POST --header "Content-type:application/x-www-form-urlencoded" \
            https://oauth2.googleapis.com/revoke?token={token}

    The token can be an access token or a refresh token. If the token is an access token and it has a corresponding refresh token, the refresh token will also be revoked.

    If the revocation is successfully processed, then the HTTP status code of the response is 200 . For error conditions, an HTTP status code 400 is returned along with an error code.