Web Sunucusu Uygulamaları için OAuth 2.0'ı Kullanma

Bu dokümanda, web sunucusu uygulamalarının Google API'lerine erişmek için OAuth 2.0 yetkilendirmesini uygulamak üzere Google API istemci kitaplıklarını veya Google OAuth 2.0 uç noktalarını nasıl kullandığı açıklanmaktadır.

OAuth 2.0 sayesinde kullanıcılar, bir uygulamayla belirli verileri paylaşırken kullanıcı adlarını, şifrelerini ve diğer bilgilerini gizli tutabilir. Örneğin, bir uygulama, kullanıcıların Google Drive'larında dosya depolamak için kullanıcılardan izin almak üzere OAuth 2.0'ı kullanabilir.

Bu OAuth 2.0 akışı, özellikle kullanıcı yetkilendirmesi içindir. Gizli bilgileri depolayabilen ve durumu koruyabilen uygulamalar için tasarlanmıştır. Düzgün şekilde yetkilendirilmiş bir web sunucusu uygulaması, kullanıcı uygulamayla etkileşimde bulunurken veya uygulamadan ayrıldıktan sonra bir API'ye erişebilir.

Web sunucusu uygulamaları, API isteklerini yetkilendirmek için sık sık hizmet hesaplarını da kullanır. Bu durum özellikle kullanıcıya özel veriler yerine projeye dayalı verilere erişmek için Cloud API'leri çağrılırken geçerlidir. Web sunucusu uygulamaları, kullanıcı yetkilendirmesiyle birlikte hizmet hesaplarını kullanabilir.

İstemci kitaplıkları

Bu sayfadaki dile özgü örneklerde OAuth 2.0 yetkilendirmesini uygulamak için Google API istemci kitaplıkları kullanılır. Kod örneklerini çalıştırmak için öncelikle dilinize ait istemci kitaplığını yüklemeniz gerekir.

Uygulamanızın OAuth 2.0 akışını yönetmek için bir Google API istemci kitaplığı kullandığınızda istemci kitaplığı, uygulamanın kendi başına yapması gereken birçok işlemi gerçekleştirir. Örneğin, uygulamanın depolanan erişim jetonlarını ne zaman kullanabileceğini veya yenileyebileceğini ve uygulamanın ne zaman yeniden izin alması gerektiğini belirler. İstemci kitaplığı, doğru yönlendirme URL'leri de oluşturur ve yetkilendirme kodlarını erişim jetonlarıyla değiştiren yönlendirme işleyicilerin uygulanmasına yardımcı olur.

Sunucu tarafı uygulamalar için Google API istemci kitaplıkları aşağıdaki dillerde kullanılabilir:

Ön koşullar

Projeniz için API'leri etkinleştirme

Google API'lerini çağıran tüm uygulamaların, API Konsolu'nda bu API'leri etkinleştirmesi gerekir.

Projeniz için bir API'yi etkinleştirmek üzere:

  1. Google API Konsolu'nda API Kitaplığı'nı açın.
  2. İstenirse bir proje seçin veya yeni bir proje oluşturun.
  3. API Kitaplığı, mevcut tüm API'leri ürün ailesine ve popülerliğe göre gruplandırarak listeler. Etkinleştirmek istediğiniz API listede görünmüyorsa arama yaparak bulun veya ait olduğu ürün ailesinde Tümünü Görüntüle'yi tıklayın.
  4. Etkinleştirmek istediğiniz API'yi seçin, ardından Etkinleştir düğmesini tıklayın.
  5. İstenirse faturalandırmayı etkinleştirin.
  6. İstenirse API'nin Hizmet Şartları'nı okuyup kabul edin.

Yetkilendirme kimlik bilgileri oluşturma

Google API'lerine erişmek için OAuth 2.0 kullanan tüm uygulamaların, uygulamayı Google'ın OAuth 2.0 sunucusuna tanımlayan yetkilendirme kimlik bilgilerine sahip olması gerekir. Aşağıdaki adımlarda, projeniz için nasıl kimlik bilgileri oluşturacağınız açıklanmaktadır. Uygulamalarınız, bu kimlik bilgilerini kullanarak ilgili proje için etkinleştirdiğiniz API'lere erişebilir.

  1. Müşteriler sayfasına gidin.
  2. Create Client'ı (İstemci Oluştur) tıklayın.
  3. Web uygulaması uygulama türünü seçin.
  4. Formu doldurun ve Create'i (Oluştur) tıklayın. PHP, Java, Python, Ruby ve .NET gibi dilleri ve çerçeveleri kullanan uygulamaların yetkili yönlendirme URI'larını belirtmesi gerekir. Yönlendirme URI'leri, OAuth 2.0 sunucusunun yanıt gönderebileceği uç noktalardır. Bu uç noktalar Google'ın doğrulama kurallarına uygun olmalıdır.

    Test için yerel makineye başvuran URI'ler belirtebilirsiniz (ör. http://localhost:8080). Bu dokümandaki tüm örneklerde yönlendirme URI'si olarak http://localhost:8080 kullanılır.

    Uygulamanızın yetkilendirme kodlarını sayfadaki diğer kaynaklara göstermemesi için uygulamanızın kimlik doğrulama uç noktalarını tasarlamanızı öneririz.

Kimlik bilgilerinizi oluşturduktan sonra API Console'dan client_secret.json dosyasını indirin. Dosyayı yalnızca uygulamanızın erişebileceği bir konumda güvenli bir şekilde saklayın.

Erişim kapsamlarını belirleme

Kapsamlar, uygulamanızın yalnızca ihtiyaç duyduğu kaynaklara erişim istemesini sağlarken kullanıcıların da uygulamanıza verdikleri erişim miktarını kontrol etmelerine olanak tanır. Bu nedenle, istenen kapsam sayısı ile kullanıcı rızası alma olasılığı arasında ters bir ilişki olabilir.

OAuth 2.0 yetkilendirmesini uygulamaya başlamadan önce uygulamanızın erişim izni gerektirecek kapsamları belirlemenizi öneririz.

Uygulamanızın, kullanıcı verilerine bağlam içinde erişim istediği artımlı yetkilendirme süreci aracılığıyla yetkilendirme kapsamlarına erişim istemesini de öneririz. Bu en iyi uygulama, kullanıcıların uygulamanızın istediği erişime neden ihtiyaç duyduğunu daha kolay anlamasına yardımcı olur.

OAuth 2.0 API Kapsamları dokümanında, Google API'lerine erişmek için kullanabileceğiniz kapsamların tam listesi yer alır.

Dile özgü şartlar

Bu belgedeki kod örneklerinden herhangi birini çalıştırmak için bir Google Hesabınız, internet erişiminiz ve bir web tarayıcınız olmalıdır. API istemci kitaplıklarından birini kullanıyorsanız aşağıdaki bölümlerde dile özgü şartlara da bakın.

PHP

Bu dokümandaki PHP kod örneklerini çalıştırmak için şunlar gerekir:

  • Komut satırı arayüzü (CLI) ve JSON uzantısı yüklü PHP 8.0 veya daha yeni bir sürüm
  • Composer bağımlılık yönetimi aracı.
  • PHP için Google API'leri İstemci Kitaplığı:

    composer require google/apiclient:^2.15.0

Daha fazla bilgi için PHP için Google API'leri İstemci Kitaplığı'na bakın.

Python

Bu dokümandaki Python kod örneklerini çalıştırmak için şunlar gerekir:

  • Python 3.7 veya sonraki sürümler
  • pip paket yönetim aracı.
  • Python 2.0 için Google API'leri İstemci Kitaplığı sürümü:
    pip install --upgrade google-api-python-client
  • Kullanıcı yetkilendirmesi için google-auth, google-auth-oauthlib ve google-auth-httplib2.
    pip install --upgrade google-auth google-auth-oauthlib google-auth-httplib2
  • Flask Python web uygulaması çerçevesi.
    pip install --upgrade flask
  • requests HTTP kitaplığı.
    pip install --upgrade requests

Python'u ve ilgili geçiş rehberini yükseltemiyorsanız Google API'leri Python istemci kitaplığı sürüm notlarını inceleyin.

Ruby

Bu belgedeki Ruby kod örneklerini çalıştırmak için şunlar gerekir:

  • Ruby 2.6 veya sonraki sürümler
  • Ruby için Google Auth Kitaplığı:

    gem install googleauth
  • Drive ve Takvim Google API'leri için istemci kitaplıkları:

    gem install google-apis-drive_v3 google-apis-calendar_v3
  • Sinatra Ruby web uygulaması çerçevesi.

    gem install sinatra

Node.js

Bu dokümandaki Node.js kod örneklerini çalıştırmak için gerekenler:

  • Node.js'nin bakım LTS, etkin LTS veya mevcut sürümü.
  • Google API'leri Node.js istemcisi:

    npm install googleapis crypto express express-session

HTTP/REST

OAuth 2.0 uç noktalarını doğrudan çağırabilmek için herhangi bir kitaplık yüklemeniz gerekmez.

OAuth 2.0 erişim jetonları alma

Aşağıdaki adımlarda, uygulamanızın kullanıcı adına API isteği gerçekleştirmek için kullanıcının iznini almak üzere Google'ın OAuth 2.0 sunucusuyla nasıl etkileşim kurduğu gösterilmektedir. Uygulamanızın, kullanıcı yetkilendirmesi gerektiren bir Google API isteğini yürütebilmesi için bu izne sahip olması gerekir.

Aşağıdaki listede bu adımlar kısaca özetlenmiştir:

  1. Uygulamanız, ihtiyaç duyduğu izinleri tanımlar.
  2. Uygulamanız, kullanıcıyı istenen izinlerin listesiyle birlikte Google'a yönlendirir.
  3. Kullanıcı, uygulamanıza izin verip vermeyeceğine karar verir.
  4. Uygulamanız, kullanıcının neye karar verdiğini öğrenir.
  5. Kullanıcı istenen izinleri verdiyse uygulamanız, kullanıcı adına API istekleri göndermek için gereken jetonları alır.

1. adım: Yetkilendirme parametrelerini ayarlayın

İlk adımınız yetkilendirme isteği oluşturmaktır. Bu istek, uygulamanızı tanımlayan ve kullanıcıdan uygulamanıza vermesi istenecek izinleri tanımlayan parametreleri ayarlar.

  • OAuth 2.0 kimlik doğrulaması ve yetkilendirmesi için bir Google istemci kitaplığı kullanıyorsanız bu parametreleri tanımlayan bir nesne oluşturup yapılandırırsınız.
  • Google OAuth 2.0 uç noktasını doğrudan çağırırsanız bir URL oluşturur ve bu URL'de parametreleri ayarlarsınız.

Aşağıdaki sekmelerde, web sunucusu uygulamaları için desteklenen yetkilendirme parametreleri tanımlanmaktadır. Dile özgü örneklerde, bu parametreleri ayarlayan bir nesneyi yapılandırmak için istemci kitaplığının veya yetkilendirme kitaplığının nasıl kullanılacağı da gösterilmektedir:

PHP

Aşağıdaki kod snippet'i, yetkilendirme isteğindeki parametreleri tanımlayan bir Google\Client() nesnesi oluşturur.

Bu nesne, uygulamanızı tanımlamak için client_secret.json dosyanızdaki bilgileri kullanır. (Bu dosya hakkında daha fazla bilgi için yetkilendirme kimlik bilgileri oluşturma bölümüne bakın.) Nesne ayrıca, uygulamanızın erişim izni istediği kapsamları ve Google'ın OAuth 2.0 sunucusundan gelen yanıtı işleyecek olan uygulamanızın kimlik doğrulama uç noktasının URL'sini de tanımlar. Son olarak kod, isteğe bağlı access_type ve include_granted_scopes parametrelerini ayarlar.

Örneğin, aşağıdaki kod bir kullanıcının Google Drive meta verilerine ve Takvim etkinliklerine salt okuma, çevrimdışı erişim ister:

use Google\Client;

$client = new Client();

// Required, call the setAuthConfig function to load authorization credentials from
// client_secret.json file.
$client->setAuthConfig('client_secret.json');

// Required, to set the scope value, call the addScope function
$client->addScope([Google\Service\Drive::DRIVE_METADATA_READONLY, Google\Service\Calendar::CALENDAR_READONLY]);

// Required, call the setRedirectUri function to specify a valid redirect URI for the
// provided client_id
$client->setRedirectUri('http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback.php');

// Recommended, 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');

// Recommended, call the setState function. Using a state value can increase your assurance that
// an incoming connection is the result of an authentication request.
$client->setState($sample_passthrough_value);

// Optional, if your application knows which user is trying to authenticate, it can use this
// parameter to provide a hint to the Google Authentication Server.
$client->setLoginHint('hint@example.com');

// Optional, call the setPrompt function to set "consent" will prompt the user for consent
$client->setPrompt('consent');

// Optional, call the setIncludeGrantedScopes function with true to enable incremental
// authorization
$client->setIncludeGrantedScopes(true);

Python

Aşağıdaki kod snippet'i, yetkilendirme isteğini oluşturmak için google-auth-oauthlib.flow modülünü kullanır.

Kod, Flow nesnesi oluşturur. Bu nesne, yetkilendirme kimlik bilgilerini oluşturduktan sonra indirdiğiniz client_secret.json dosyasındaki bilgileri kullanarak uygulamanızı tanımlar. Bu nesne, uygulamanızın erişim izni istediği kapsamları ve uygulamanızın kimlik doğrulama uç noktasının URL'sini de tanımlar. Bu URL, Google'ın OAuth 2.0 sunucusundan gelen yanıtı işler. Son olarak kod, isteğe bağlı access_type ve include_granted_scopes parametrelerini ayarlar.

Örneğin, aşağıdaki kod bir kullanıcının Google Drive meta verilerine ve Takvim etkinliklerine salt okuma, çevrimdışı erişim ister:

import google.oauth2.credentials
import google_auth_oauthlib.flow

# Required, call the from_client_secrets_file method to retrieve the client ID from a
# client_secret.json file. The client ID (from that file) and access scopes are required. (You can
# also use the from_client_config method, which passes the client configuration as it originally
# appeared in a client secrets file but doesn't access the file itself.)
flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file('client_secret.json',
    scopes=['https://www.googleapis.com/auth/drive.metadata.readonly',
            'https://www.googleapis.com/auth/calendar.readonly'])

# Required, 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(
    # Recommended, 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',
    # Optional, enable incremental authorization. Recommended as a best practice.
    include_granted_scopes='true',
    # Optional, if your application knows which user is trying to authenticate, it can use this
    # parameter to provide a hint to the Google Authentication Server.
    login_hint='hint@example.com',
    # Optional, set prompt to 'consent' will prompt the user for consent
    prompt='consent')

Ruby

Uygulamanızda bir istemci nesnesi yapılandırmak için oluşturduğunuz client_secrets.json dosyasını kullanın. Bir istemci nesnesi yapılandırırken uygulamanızın erişmesi gereken kapsamları ve uygulamanızın kimlik doğrulama uç noktasının URL'sini belirtirsiniz. Bu URL, OAuth 2.0 sunucusundan gelen yanıtı işler.

Örneğin, aşağıdaki kod bir kullanıcının Google Drive meta verilerine ve Takvim etkinliklerine salt okuma, çevrimdışı erişim ister:

require 'googleauth'
require 'googleauth/web_user_authorizer'
require 'googleauth/stores/redis_token_store'

require 'google/apis/drive_v3'
require 'google/apis/calendar_v3'

# Required, call the from_file method to retrieve the client ID from a
# client_secret.json file.
client_id = Google::Auth::ClientId.from_file('/path/to/client_secret.json')

# Required, scope value 
# Access scopes for two non-Sign-In scopes: Read-only Drive activity and Google Calendar.
scope = ['Google::Apis::DriveV3::AUTH_DRIVE_METADATA_READONLY',
         'Google::Apis::CalendarV3::AUTH_CALENDAR_READONLY']

# Required, Authorizers require a storage instance to manage long term persistence of
# access and refresh tokens.
token_store = Google::Auth::Stores::RedisTokenStore.new(redis: Redis.new)

# Required, 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.
callback_uri = '/oauth2callback'

# To use OAuth2 authentication, we need access to a CLIENT_ID, CLIENT_SECRET, AND REDIRECT_URI
# from the client_secret.json file. To get these credentials for your application, visit
# https://console.cloud.google.com/apis/credentials.
authorizer = Google::Auth::WebUserAuthorizer.new(client_id, scope,
                                                token_store, callback_uri)

Uygulamanız, OAuth 2.0 işlemlerini (ör. yetkilendirme isteği URL'leri oluşturma ve HTTP isteklerine erişim jetonları uygulama) gerçekleştirmek için istemci nesnesini kullanır.

Node.js

Aşağıdaki kod snippet'i, yetkilendirme isteğindeki parametreleri tanımlayan bir google.auth.OAuth2 nesnesi oluşturur.

Bu nesne, uygulamanızı tanımlamak için client_secret.json dosyanızdaki bilgileri kullanır. Erişim jetonu almak için kullanıcıdan izin istemek üzere kullanıcıyı bir izin sayfasına yönlendirirsiniz. İzin sayfası URL'si oluşturmak için:

const {google} = require('googleapis');
const crypto = require('crypto');
const express = require('express');
const session = require('express-session');

/**
 * To use OAuth2 authentication, we need access to a CLIENT_ID, CLIENT_SECRET, AND REDIRECT_URI
 * from the client_secret.json file. To get these credentials for your application, visit
 * https://console.cloud.google.com/apis/credentials.
 */
const oauth2Client = new google.auth.OAuth2(
  YOUR_CLIENT_ID,
  YOUR_CLIENT_SECRET,
  YOUR_REDIRECT_URL
);

// Access scopes for two non-Sign-In scopes: Read-only Drive activity and Google Calendar.
const scopes = [
  'https://www.googleapis.com/auth/drive.metadata.readonly',
  'https://www.googleapis.com/auth/calendar.readonly'
];

// Generate a secure random state value.
const state = crypto.randomBytes(32).toString('hex');

// Store state in the session
req.session.state = state;

// Generate a url that asks permissions for the Drive activity and Google Calendar scope
const authorizationUrl = oauth2Client.generateAuthUrl({
  // 'online' (default) or 'offline' (gets refresh_token)
  access_type: 'offline',
  /** Pass in the scopes array defined above.
    * Alternatively, if only one scope is needed, you can pass a scope URL as a string */
  scope: scopes,
  // Enable incremental authorization. Recommended as a best practice.
  include_granted_scopes: true,
  // Include the state parameter to reduce the risk of CSRF attacks.
  state: state
});

Önemli Not: refresh_token yalnızca ilk yetkilendirmede döndürülür. Daha fazla bilgiyi burada bulabilirsiniz.

HTTP/REST

Google'ın OAuth 2.0 uç noktası https://accounts.google.com/o/oauth2/v2/auth adresindedir. Bu uç noktaya yalnızca HTTPS üzerinden erişilebilir. Düz HTTP bağlantıları reddedilir.

Google yetkilendirme sunucusu, web sunucusu uygulamaları için aşağıdaki sorgu dizesi parametrelerini destekler:

Parametreler
client_id Zorunlu

Uygulamanızın istemci kimliği. Bu değeri Cloud Console'daki İstemciler sayfasında bulabilirsiniz.

redirect_uri Zorunlu

Kullanıcı yetkilendirme akışını tamamladıktan sonra API sunucusunun kullanıcıyı nereye yönlendireceğini belirler. Değer, istemcinizin Cloud Console İstemciler sayfasında yapılandırdığınız OAuth 2.0 istemcisinin yetkili yönlendirme URI'larından biriyle tam olarak eşleşmelidir. Bu değer, sağlanan client_id için yetkili bir yönlendirme URI'si ile eşleşmiyorsa redirect_uri_mismatch hatası alırsınız.

http veya https şeması, büyük/küçük harf ve sondaki eğik çizginin ("/") eşleşmesi gerektiğini unutmayın.

response_type Zorunlu

Google OAuth 2.0 uç noktasının bir yetkilendirme kodu döndürüp döndürmeyeceğini belirler.

Web sunucusu uygulamaları için parametre değerini code olarak ayarlayın.

scope Zorunlu

Uygulamanızın kullanıcı adına erişebileceği kaynakları tanımlayan, boşlukla ayrılmış kapsam listesi. Bu değerler, Google'ın kullanıcıya gösterdiği kullanıcı rızası ekranını bilgilendirir.

Kapsamlar, uygulamanızın yalnızca ihtiyaç duyduğu kaynaklara erişim isteğinde bulunmasını sağlarken kullanıcıların da uygulamanıza verdikleri erişim miktarını kontrol etmelerine olanak tanır. Bu nedenle, istenen kapsam sayısı ile kullanıcı rızası alma olasılığı arasında ters bir ilişki vardır.

Uygulamanızın, mümkün olduğunda yetkilendirme kapsamlarına bağlam içinde erişim isteğinde bulunmasını öneririz. Kademeli yetkilendirme kullanarak kullanıcı verilerine bağlam içinde erişim isteğinde bulunarak kullanıcıların, uygulamanızın neden istediği erişime ihtiyaç duyduğunu anlamalarına yardımcı olursunuz.

access_type Önerilen

Uygulamanızın, kullanıcı tarayıcıda olmadığında erişim jetonlarını yenileyip yenileyemeyeceğini belirtir. Geçerli parametre değerleri, varsayılan değer olan online ve offline'dir.

Kullanıcı tarayıcıda olmadığında uygulamanızın erişim jetonlarını yenilemesi gerekiyorsa değeri offline olarak ayarlayın. Bu, erişim jetonlarını yenileme yöntemidir. Bu yöntem, dokümanın ilerleyen bölümlerinde açıklanmıştır. Bu değer, Google yetkilendirme sunucusuna, uygulamanızın bir yetkilendirme kodunu jetonlarla ilk kez değiştirdiğinde bir yenileme jetonu ve erişim jetonu döndürmesini söyler.

state Önerilen

Uygulamanızın, yetkilendirme isteğiniz ile yetkilendirme sunucusunun yanıtı arasındaki durumu korumak için kullandığı dize değerini belirtir. Kullanıcı, uygulamanızın erişim isteğini kabul ettikten veya reddettikten sonra sunucu, redirect_uri URL sorgu bileşeninde (?) name=value çifti olarak gönderdiğiniz tam değeri döndürür.

Bu parametreyi, kullanıcıyı uygulamanızdaki doğru kaynağa yönlendirme, tek seferlik rastgele sayılar gönderme ve siteler arası istek sahteciliğini azaltma gibi çeşitli amaçlarla kullanabilirsiniz. redirect_uri tahmin edilebileceğinden, state değeri kullanmak gelen bir bağlantının kimlik doğrulama isteğinin sonucu olduğuna dair güvencenizi artırabilir. Rastgele bir dize oluşturursanız veya bir çerezin ya da istemcinin durumunu yakalayan başka bir değerin karmasını kodlarsanız isteğin ve yanıtın aynı tarayıcıdan geldiğinden emin olmak için yanıtı doğrulayabilirsiniz. Bu, siteler arası istek sahteciliği gibi saldırılara karşı koruma sağlar. state jetonunun nasıl oluşturulacağı ve onaylanacağıyla ilgili bir örnek için OpenID Connect belgelerine bakın.

include_granted_scopes İsteğe bağlı

Uygulamaların, bağlamdaki ek kapsamlara erişim istemek için artımlı yetkilendirmeyi kullanmasına olanak tanır. Bu parametrenin değerini true olarak ayarlarsanız ve yetkilendirme isteği onaylanırsa yeni erişim jetonu, kullanıcının daha önce uygulamaya erişim izni verdiği tüm kapsamları da kapsar. Örnekler için artımlı yetkilendirme bölümüne bakın.

login_hint İsteğe bağlı

Uygulamanız, hangi kullanıcının kimlik doğrulaması yapmaya çalıştığını biliyorsa Google Kimlik Doğrulama Sunucusu'na ipucu sağlamak için bu parametreyi kullanabilir. Sunucu, oturum açma formundaki e-posta alanını önceden doldurarak veya uygun çoklu giriş oturumunu seçerek giriş akışını basitleştirmek için ipucunu kullanır.

Parametre değerini, kullanıcının Google kimliğine eşdeğer bir e-posta adresi veya sub tanımlayıcısı olarak ayarlayın.

prompt İsteğe bağlı

Kullanıcıya sunulacak istemlerin boşlukla ayrılmış, büyük/küçük harfe duyarlı listesi. Bu parametreyi belirtmezseniz kullanıcıdan yalnızca projeniz ilk kez erişim istediğinde onay istenir. Daha fazla bilgi için Yeniden izin isteme bölümüne bakın.

Olası değerler:

none Kimlik doğrulama veya kullanıcı rızası ekranları göstermeyin. Diğer değerlerle birlikte belirtilmemelidir.
consent Kullanıcıdan izin isteyin.
select_account Kullanıcıdan bir hesap seçmesini isteyin.

2. adım: Google'ın OAuth 2.0 sunucusuna yönlendirin

Kimlik doğrulama ve yetkilendirme sürecini başlatmak için kullanıcıyı Google'ın OAuth 2.0 sunucusuna yönlendirin. Bu durum genellikle uygulamanızın kullanıcının verilerine ilk kez erişmesi gerektiğinde ortaya çıkar. Artımlı yetkilendirme söz konusu olduğunda bu adım, uygulamanızın erişim izni olmayan ek kaynaklara ilk kez erişmesi gerektiğinde de gerçekleşir.

PHP

  1. Google'ın OAuth 2.0 sunucusundan erişim istemek için bir URL oluşturun:
    $auth_url = $client->createAuthUrl();
  2. Kullanıcıyı $auth_url adresine yönlendirin:
    header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));

Python

Bu örnekte, Flask web uygulaması çerçevesi kullanılarak kullanıcının yetkilendirme URL'sine nasıl yönlendirileceği gösterilmektedir:

return flask.redirect(authorization_url)

Ruby

  1. Google'ın OAuth 2.0 sunucusundan erişim istemek için bir URL oluşturun:
    auth_uri = authorizer.get_authorization_url(request: request)
  2. Kullanıcıyı auth_uri adresine yönlendirin.

Node.js

  1. Google'ın OAuth 2.0 sunucusundan erişim istemek için 1. adım'da oluşturulan authorizationUrl URL'sini generateAuthUrl yöntemiyle kullanın.
  2. Kullanıcıyı authorizationUrl adresine yönlendirin.
    res.redirect(authorizationUrl);

HTTP/REST

Google'ın yetkilendirme sunucusuna örnek yönlendirme

Aşağıda, okunabilirliği artırmak için satır sonları ve boşluklar içeren örnek bir URL gösterilmektedir.

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

İstek URL'sini oluşturduktan sonra kullanıcıyı bu URL'ye yönlendirin.

Google'ın OAuth 2.0 sunucusu, kullanıcının kimliğini doğrular ve uygulamanızın istenen kapsamlara erişmesi için kullanıcıdan izin alır. Yanıt, belirttiğiniz yönlendirme URL'si kullanılarak uygulamanıza geri gönderilir.

3. adım: Google, kullanıcıdan izin ister

Bu adımda kullanıcı, uygulamanıza istenen erişimi verip vermeyeceğine karar verir. Bu aşamada Google, uygulamanızın adını ve kullanıcının yetkilendirme kimlik bilgileriyle erişim izni istediği Google API'leri hizmetlerini gösteren bir izin penceresi ve verilecek erişim kapsamlarının özetini gösterir. Kullanıcı, uygulamanızın istediği bir veya daha fazla kapsama erişim izni vermeyi kabul edebilir ya da isteği reddedebilir.

Uygulamanızın bu aşamada herhangi bir işlem yapması gerekmez. Google'ın OAuth 2.0 sunucusundan erişim izni verilip verilmediğini belirten yanıtı bekler. Bu yanıt, bir sonraki adımda açıklanmıştır.

Hatalar

Google'ın OAuth 2.0 yetkilendirme uç noktasına gönderilen istekler, beklenen kimlik doğrulama ve yetkilendirme akışları yerine kullanıcılara yönelik hata mesajları gösterebilir. Sık karşılaşılan hata kodları ve önerilen çözümler şunlardır:

admin_policy_enforced

Google Hesabı, Google Workspace yöneticisinin politikaları nedeniyle istenen bir veya daha fazla kapsamı yetkilendiremiyor. Yöneticilerin, OAuth istemci kimliğinize açıkça erişim izni verilene kadar tüm kapsamlara veya hassas ve kısıtlanmış kapsamlara erişimi nasıl kısıtlayabileceği hakkında daha fazla bilgi için Google Workspace verilerine hangi üçüncü taraf uygulamalar ve dahili uygulamaların erişebileceğini yönetme başlıklı Google Workspace Yönetici Yardım makalesini inceleyin.

disallowed_useragent

Yetkilendirme uç noktası, Google'ın OAuth 2.0 Politikaları tarafından izin verilmeyen yerleşik bir kullanıcı aracısı içinde gösteriliyor.

iOS ve macOS geliştiricileri, WKWebView uygulamasında yetkilendirme isteklerini açarken bu hatayla karşılaşabilir. Geliştiriciler bunun yerine iOS için Google ile Oturum Açma veya OpenID Foundation'ın iOS için AppAuth gibi iOS kitaplıklarını kullanmalıdır.

Web geliştiricileri, bir iOS veya macOS uygulaması yerleşik bir kullanıcı aracısında genel bir web bağlantısı açtığında ve kullanıcı sitenizden Google'ın OAuth 2.0 yetkilendirme uç noktasına gittiğinde bu hatayla karşılaşabilir. Geliştiriciler, genel bağlantıların işletim sisteminin varsayılan bağlantı işleyicisinde açılmasına izin vermelidir. Bu işleyiciler arasında hem Geçiş Bağlantıları işleyicileri hem de varsayılan tarayıcı uygulaması yer alır. SFSafariViewController kitaplığı da desteklenen bir seçenektir.

org_internal

İstekteki OAuth istemci kimliği, belirli bir Google Cloud kuruluşundaki Google Hesaplarına erişimi sınırlayan bir projenin parçasıdır. Bu yapılandırma seçeneği hakkında daha fazla bilgi için OAuth kullanıcı rızası ekranınızı ayarlama yardım makalesindeki Kullanıcı türü bölümüne bakın.

invalid_client

OAuth istemci gizli anahtarı yanlış. Bu istek için kullanılan istemci kimliği ve gizli anahtar dahil olmak üzere OAuth istemci yapılandırmasını inceleyin.

deleted_client

İsteği göndermek için kullanılan OAuth istemcisi silinmiştir. Silme işlemi manuel olarak veya kullanılmayan istemciler söz konusu olduğunda otomatik olarak yapılabilir. Silinen müşteriler, silme işleminden sonraki 30 gün içinde geri yüklenebilir. Daha fazla bilgi edinin .

invalid_grant

Erişim jetonunu yenilerken veya artımlı yetkilendirme kullanırken jetonun süresi dolmuş veya geçersiz kılınmış olabilir. Kullanıcının kimliğini tekrar doğrulayın ve yeni jetonlar almak için kullanıcıdan izin isteyin. Bu hatayı görmeye devam ederseniz uygulamanızın doğru şekilde yapılandırıldığından ve isteğinizde doğru jetonları ve parametreleri kullandığınızdan emin olun. Aksi takdirde, kullanıcı hesabı silinmiş veya devre dışı bırakılmış olabilir.

redirect_uri_mismatch

Yetkilendirme isteğinde iletilen redirect_uri, OAuth istemci kimliği için yetkilendirilmiş bir yönlendirme URI'siyle eşleşmiyor. Google Cloud Console'un İstemciler sayfasında yetkilendirilmiş yönlendirme URI'lerini inceleyin.

redirect_uri parametresi, kullanımdan kaldırılan ve artık desteklenmeyen OAuth bant dışı (OOB) akışına başvuruyor olabilir. Entegrasyonunuzu güncellemek için geçiş rehberini inceleyin.

invalid_request

İsteğinizle ilgili bir sorun oluştu. Bunun birkaç nedeni olabilir:

  • İstek doğru şekilde biçimlendirilmemiş.
  • İstekte gerekli parametreler eksikti.
  • İstek, Google'ın desteklemediği bir yetkilendirme yöntemi kullanıyor. OAuth entegrasyonunuzun önerilen bir entegrasyon yöntemi kullandığını doğrulayın.

4. adım: OAuth 2.0 sunucu yanıtını işleme

OAuth 2.0 sunucusu, istekte belirtilen URL'yi kullanarak uygulamanızın erişim isteğine yanıt verir.

Kullanıcı erişim isteğini onaylarsa yanıt bir yetkilendirme kodu içerir. Kullanıcı isteği onaylamazsa yanıtta bir hata mesajı yer alır. Web sunucusuna döndürülen yetkilendirme kodu veya hata mesajı, aşağıdaki örneklerde gösterildiği gibi sorgu dizesinde görünür:

Hata yanıtı:

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

Yetkilendirme kodu yanıtı:

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

Örnek OAuth 2.0 sunucu yanıtı

Google Drive'ınızdaki dosyaların meta verilerini görüntülemek için salt okuma erişimi ve Google Takvim etkinliklerinizi görüntülemek için salt okuma erişimi isteyen aşağıdaki örnek URL'yi tıklayarak bu akışı test edebilirsiniz:

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

OAuth 2.0 akışını tamamladıktan sonra tarayıcınız sizi OAuth akışlarını test etmeye yönelik bir araç olan OAuth 2.0 Playground'a yönlendirir. OAuth 2.0 Playground'un yetkilendirme kodunu otomatik olarak yakaladığını göreceksiniz.

5. adım: Yenileme ve erişim jetonları için yetkilendirme kodu değiş tokuşu yapın

Web sunucusu, yetkilendirme kodunu aldıktan sonra yetkilendirme kodunu bir erişim jetonuyla değiştirebilir.

PHP

Bir yetkilendirme kodunu erişim jetonuyla değiştirmek için fetchAccessTokenWithAuthCode yöntemini kullanın:

$access_token = $client->fetchAccessTokenWithAuthCode($_GET['code']);

Python

Geri çağırma sayfanızda, yetkilendirme sunucusu yanıtını doğrulamak için google-auth kitaplığını kullanın. Ardından, bu yanıttaki yetkilendirme kodunu bir erişim jetonuyla değiştirmek için flow.fetch_token yöntemini kullanın:

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 browser session storage, but for security: client_id, client_secret,
# and token_uri are instead stored only on the backend server.
credentials = flow.credentials
flask.session['credentials'] = {
    'token': credentials.token,
    'refresh_token': credentials.refresh_token,
    'granted_scopes': credentials.granted_scopes}

Ruby

Geri çağırma sayfanızda, yetkilendirme sunucusu yanıtını doğrulamak için googleauth kitaplığını kullanın. Yetkilendirme kodunu kaydetmek ve başlangıçta yetkilendirme isteyen URL'ye geri yönlendirmek için authorizer.handle_auth_callback_deferred yöntemini kullanın. Bu, sonuçları geçici olarak kullanıcının oturumunda saklayarak kodun değişimini erteler.

  target_url = Google::Auth::WebUserAuthorizer.handle_auth_callback_deferred(request)
  redirect target_url

Node.js

Yetkilendirme kodunu erişim jetonuyla değiştirmek için getToken yöntemini kullanın:

const url = require('url');

// Receive the callback from Google's OAuth 2.0 server.
app.get('/oauth2callback', async (req, res) => {
  let q = url.parse(req.url, true).query;

  if (q.error) { // An error response e.g. error=access_denied
    console.log('Error:' + q.error);
  } else if (q.state !== req.session.state) { //check state value
    console.log('State mismatch. Possible CSRF attack');
    res.end('State mismatch. Possible CSRF attack');
  } else { // Get access and refresh tokens (if access_type is offline)

    let { tokens } = await oauth2Client.getToken(q.code);
    oauth2Client.setCredentials(tokens);
});

HTTP/REST

Bir yetkilendirme kodunu erişim jetonuyla değiştirmek için https://oauth2.googleapis.com/token uç noktasını çağırın ve aşağıdaki parametreleri ayarlayın:

Alanlar
client_id Cloud Console İstemciler sayfasından alınan istemci kimliği.
client_secret İsteğe bağlı

Cloud Console İstemciler sayfasından alınan istemci gizli anahtarı.

code İlk istekten döndürülen yetkilendirme kodu.
grant_type OAuth 2.0 spesifikasyonunda tanımlandığı gibi, bu alanın değeri authorization_code olarak ayarlanmalıdır.
redirect_uri Belirli bir client_id için Cloud Console İstemciler sayfasında projeniz için listelenen yönlendirme URI'lerinden biri.

DPoP kullanımı isteğe bağlı olsa da daha fazla güvenlik için önerilir. DPoP'un güvenliği, özel anahtarın tek bir cihazla sınırlandırılmasına bağlıdır. Anahtarı, cihaz dışına kopyalanamayacak şekilde (ör. TPM'ler, Güvenli Alanlar veya diğer donanım destekli anahtar depoları kullanarak) saklamanızı öneririz. DPoP'u kullanmak için uygulamanızın, jeton uç noktasına yapılan her istek için yeni ve benzersiz bir DPoP kanıtı JWT'si oluşturması ve bunu HTTP istek başlığı olarak eklemesi gerekir.

Başlık Zorunlu Açıklama
DPoP İsteğe bağlı DPoP kanıtı, özel anahtarın sahipliğini kanıtlayan bir JWT'dir. Bu bir parametre değil, başlıktır. Sağlanırsa döndürülen jetonlar bu anahtara bağlanır. Her istek için yeni ve benzersiz bir kanıt oluşturulmalı ve istekle eşleşen htm (HTTP yöntemi) ve htu (HTTP URI) taleplerini içermelidir.

Aşağıdaki snippet'te örnek bir istek gösterilmektedir:

POST /token HTTP/1.1
Host: oauth2.googleapis.com
Content-Type: application/x-www-form-urlencoded
DPoP: eyJ0eXAiOiJkcG9wK2p3dCIsImFsZyI6IkVTMjU2IiwiandrIjp7Imt0eSI6Ik\
 VDIiwieCI6Imw4dEZyaHgtMzR0VjNoUklDUkRZOXpDa0RscEJoRjQyVVFVZldWQVdCR\
 nMiLCJ5IjoiOVZFNGpmX09rX282NHpiVFRsY3VOSmFqSG10NnY5VERWclUwQ2R2R1JE\
 QSIsImNydiI6IlAtMjU2In19.eyJqdGkiOiItQndDM0VTYzZhY2MybFRjIiwiaHRtIj\
 oiUE9TVCIsImh0dSI6Imh0dHBzOi8vc2VydmVyLmV4YW1wbGUuY29tL3Rva2VuIiwia\
 WF0IjoxNTYyMjYyNjE2fQ.2-GxA6T8lP4vfrg8v-FdWP0A0zdrj8igiMLvqRMUvwnQg\
 4PtFLbdLXiOSsX0x7NVY-FNyJK70nfbV37xRZT3Lg

code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7&
client_id=your_client_id&
redirect_uri=https%3A//developers.google.com/oauthplayground&
grant_type=authorization_code

DPoP kanıtı oluşturma

Aşağıdaki adımlarda, komut satırından OpenSSL kullanarak DPoP kanıtının nasıl oluşturulacağı gösterilmektedir:

  1. EC P-256 anahtar çifti oluşturma:
    openssl ecparam -name prime256v1 -genkey -noout -out dpop_private.pem
    openssl ec -in dpop_private.pem -pubout -out dpop_public.pem
  2. DPoP üstbilgisini oluşturun:

    Üstbilgi; typ, alg ve jwk (ortak anahtar) hak taleplerini içermelidir. x ve y değerleri, EC ortak anahtarınızın Base64Url kodlu koordinatlarıdır. Bu JSON'u Base64Url ile kodlayın:

    {
      "typ":"dpop+jwt",
      "alg":"ES256",
      "jwk": {
        "kty":"EC",
        "x":"YOUR_PUBLIC_KEY_X",
        "y":"YOUR_PUBLIC_KEY_Y",
        "crv":"P-256"
      }
    }
  3. DPoP yükünü oluşturun:

    Yükte jti (istek için benzersiz bir tanımlayıcı), htm (HTTP yöntemi, ör. POST), htu (HTTP URI, ör. https://oauth2.googleapis.com/token) ve iat (veriliş zamanı) bulunmalıdır. Önceki bir isteğe verilen yanıtta DPoP-Nonce üstbilgisinde sunucudan bir tek seferlik rastgele sayı aldıysanız bu tek seferlik rastgele sayı değerini bir nonce talebine eklemeniz gerekir. Tek seferlik rastgele sayı talebi, yetkilendirme kodu alışverişleri için isteğe bağlıdır ve yalnızca daha önce DPoP-Nonce üstbilgisi alındığında kullanılır. Bu JSON'u Base64Url ile kodlayın:

    {
      "jti":"JTI_VALUE",
      "htm":"POST",
      "htu":"https://oauth2.googleapis.com/token",
      "iat":YOUR_JWT_ISSUED_TIME,
      "nonce":"SERVER_PROVIDED_NONCE"
    }

    jti değeri, exchange türüne bağlıdır:

    • Yetkilendirme kodu değişimleri için jti, yetkilendirme kodunun Base64Url kodlamalı SHA256 karması olmalıdır: "jti":"BASE64URL(SHA256(AUTHORIZATION_CODE))".
    • Yenileme jetonu değişimleri için jti, istek başına benzersiz bir tanımlayıcı olmalıdır: "jti":"YOUR_UNIQUE_PER_REQUEST_IDENTIFIER".
  4. İspatı imzalama:

    Kodlanmış başlığı ve yükü bir nokta (.) ile birleştirin, ardından sonucu ES256 kullanarak özel anahtarınızla imzalayın. JWS'nin, imzanın ham R | S birleştirilmiş biçimde (P-256 için 64 bayt) olmasını gerektirdiğini unutmayın. Doğrudan OpenSSL kullanıyorsanız varsayılan ASN.1 DER kodlu imzayı bu ham biçime dönüştürmeniz gerekir.

Başarılı bir değişim, jetonları içeren bir 200 OK yanıtıyla belirtilir. Değişim sırasında geçerli bir DPoP kanıtı kullanılırsa Google'ın döndürdüğü yenileme jetonu, anahtarınıza DPoP ile bağlanır ancak erişim jetonları DPoP ile bağlanmaz. Erişim jetonları, DPoP yerine Bearer token_type değerini korur. Ayrıca Google, yanıtta bir DPoP-Nonce HTTP üst bilgisi döndürür. İstemciniz bu tek seferlik rastgele sayıyı önbelleğe almalı ve sonraki isteklerde (ör. yenileme jetonunu yeni bir erişim jetonuyla değiştirirken veya DPoP korumalı API'leri çağırırken) DPoP kanıtının nonce talebine dahil etmelidir. Bu erken verilen tek seferlik rastgele sayıyı kullanarak bir sonraki isteğinizde fazladan gidiş dönüş hatasını (use_dpop_nonce) önleyebilirsiniz.

DPoP'ye bağlı yenileme jetonlarıyla yapılan jeton değişimi istekleri için DPoP kanıtları eklenmelidir.

Başarısız değişim, DPoP başlığı beklendiği halde eksikse, geçersizse veya kanıt, jetona bağlı olandan farklı bir anahtar kullanıyorsa gerçekleşir. Bu durumlarda sunucu 400 Bad Request hatası döndürür. DPoP kanıtında eşleşmeyen htm veya htu talepleri, süresi dolmuş bir iat, yeniden kullanılan bir jti veya geçersiz bir imza varsa Google, invalid_dpop_proof hata kodunu döndürür. Yenileme jetonu değişimi sırasında olduğu gibi bir DPoP tek seferlik rastgele sayısı gerekiyorsa ve DPoP kanıtında nonce talebi eksikse veya tek seferlik rastgele sayı değeri sunucu tarafından kabul edilemiyorsa (ör. süresi dolmuş, zaten kullanılmış veya yanlışsa) Google, sonraki bir istekte kullanabileceğiniz yeni bir tek seferlik rastgele sayı içeren DPoP-Nonce HTTP üstbilgisiyle birlikte use_dpop_nonce hata kodu döndürür. Diğer hatalar invalid_grant döndürebilir.

Google, kısa süreli bir erişim jetonu ve yenileme jetonu içeren bir JSON nesnesi döndürerek bu isteğe yanıt verir. Yenileme jetonunun yalnızca uygulamanız Google'ın yetkilendirme sunucusuna gönderilen ilk istekte access_type parametresini offline olarak ayarladıysa döndürüldüğünü unutmayın.

Yanıtta aşağıdaki alanlar bulunur:

Alanlar
access_token Uygulamanızın bir Google API isteğini yetkilendirmek için gönderdiği jeton.
expires_in Erişim jetonunun saniye cinsinden kalan kullanım ömrü.
refresh_token Yeni bir erişim jetonu almak için kullanabileceğiniz jeton. Yenileme jetonları, kullanıcı erişimi iptal edene veya yenileme jetonunun süresi dolana kadar geçerlidir. DPoP kullanıldıysa yenileme jetonu, DPoP kanıtını imzalamak için kullanılan özel anahtara bağlıdır. Bu alan, yalnızca Google'ın yetkilendirme sunucusuna gönderilen ilk istekte access_type parametresini offline olarak ayarladıysanız bu yanıtta yer alır.
refresh_token_expires_in Yenileme jetonunun saniye cinsinden kalan kullanım ömrü. Bu değer yalnızca kullanıcı zamana dayalı erişim izni verdiğinde ayarlanır.
scope access_token tarafından verilen erişim kapsamları, boşlukla ayrılmış, büyük/küçük harfe duyarlı dizelerden oluşan bir liste olarak ifade edilir.
token_type Döndürülen jetonun türü. DPoP kullanılsa bile bu değer her zaman Bearer olur.

Aşağıdaki snippet'te, DPoP kullanıldığında başarılı bir yanıt başlığı ve gövdesi örneği gösterilmektedir:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
DPoP-Nonce: AN3XwJjZsjnb0ZuWkRlek8QU7wY-Zhf-5IP6tO0tORz0KgtDT1Bo8FX-w4nz3r5lnepI

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

Hatalar

Yetkilendirme kodunu erişim jetonuyla değiştirirken beklenen yanıt yerine aşağıdaki hatayla karşılaşabilirsiniz. Sık karşılaşılan hata kodları ve önerilen çözümler bu bölümde listelenmiştir.

invalid_grant

Sağlanan yetkilendirme kodu geçersiz veya yanlış biçimde. Kullanıcıdan tekrar izin istemek için OAuth işlemini yeniden başlatarak yeni bir kod isteyin.

6. adım: Kullanıcıların hangi kapsamlara izin verdiğini kontrol edin

Birden fazla izin (kapsam) istediğinizde kullanıcılar uygulamanıza tüm izinlere erişim hakkı vermeyebilir. Uygulamanız, gerçekte hangi kapsamların verildiğini doğrulamalı ve bazı izinlerin reddedildiği durumları, genellikle reddedilen kapsamlara dayalı özellikleri devre dışı bırakarak sorunsuz bir şekilde ele almalıdır.

Ancak istisnalar bulunmaktadır. Alan genelinde yetki devri olan Google Workspace Enterprise uygulamaları veya Güvenilir olarak işaretlenen uygulamalar, ayrıntılı izinler için kullanıcı rızası ekranını atlar. Bu uygulamalarda kullanıcılar ayrıntılı kullanıcı rızası ekranını görmez. Bunun yerine, uygulamanız istenen tüm kapsamları alır veya hiçbirini almaz.

Daha ayrıntılı bilgi için Ayrıntılı izinleri işleme başlıklı makaleyi inceleyin.

PHP

Kullanıcının hangi kapsamları verdiğini kontrol etmek için getGrantedScope() yöntemini kullanın:

// Space-separated string of granted scopes if it exists, otherwise null.
$granted_scopes = $client->getOAuth2Service()->getGrantedScope();

// Determine which scopes user granted and build a dictionary
$granted_scopes_dict = [
  'Drive' => str_contains($granted_scopes, Google\Service\Drive::DRIVE_METADATA_READONLY),
  'Calendar' => str_contains($granted_scopes, Google\Service\Calendar::CALENDAR_READONLY)
];

Python

Döndürülen credentials nesnesinin bir granted_scopes özelliği vardır. Bu özellik, kullanıcının uygulamanıza verdiği kapsamların listesidir.

credentials = flow.credentials
flask.session['credentials'] = {
    'token': credentials.token,
    'refresh_token': credentials.refresh_token,
    'granted_scopes': credentials.granted_scopes}

Aşağıdaki işlev, kullanıcının uygulamanıza hangi kapsamları verdiğini kontrol eder.

def check_granted_scopes(credentials):
  features = {}
  if 'https://www.googleapis.com/auth/drive.metadata.readonly' in credentials['granted_scopes']:
    features['drive'] = True
  else:
    features['drive'] = False

  if 'https://www.googleapis.com/auth/calendar.readonly' in credentials['granted_scopes']:
    features['calendar'] = True
  else:
    features['calendar'] = False

  return features

Ruby

Tek seferde birden fazla kapsam istediğinizde, credentials nesnesinin scope özelliği aracılığıyla hangi kapsamların verildiğini kontrol edin.

# User authorized the request. Now, check which scopes were granted.
if credentials.scope.include?(Google::Apis::DriveV3::AUTH_DRIVE_METADATA_READONLY)
  # User authorized read-only Drive activity permission.
  # Calling the APIs, etc
else
  # User didn't authorize read-only Drive activity permission.
  # Update UX and application accordingly
end

# Check if user authorized Calendar read permission.
if credentials.scope.include?(Google::Apis::CalendarV3::AUTH_CALENDAR_READONLY)
  # User authorized Calendar read permission.
  # Calling the APIs, etc.
else
  # User didn't authorize Calendar read permission.
  # Update UX and application accordingly
end

Node.js

Tek seferde birden fazla kapsam istediğinizde, tokens nesnesinin scope özelliği aracılığıyla hangi kapsamların verildiğini kontrol edin.

// User authorized the request. Now, check which scopes were granted.
if (tokens.scope.includes('https://www.googleapis.com/auth/drive.metadata.readonly'))
{
  // User authorized read-only Drive activity permission.
  // Calling the APIs, etc.
}
else
{
  // User didn't authorize read-only Drive activity permission.
  // Update UX and application accordingly
}

// Check if user authorized Calendar read permission.
if (tokens.scope.includes('https://www.googleapis.com/auth/calendar.readonly'))
{
  // User authorized Calendar read permission.
  // Calling the APIs, etc.
}
else
{
  // User didn't authorize Calendar read permission.
  // Update UX and application accordingly
}

HTTP/REST

Kullanıcının uygulamanıza belirli bir kapsam için erişim izni verip vermediğini kontrol etmek için erişim jetonu yanıtındaki scope alanını inceleyin. erişim jetonu tarafından verilen erişim kapsamları, boşlukla ayrılmış ve büyük/küçük harfe duyarlı dizelerden oluşan bir liste olarak ifade edilir.

Örneğin, aşağıdaki örnek erişim jetonu yanıtı, kullanıcının uygulamanıza salt okunur Drive etkinliği ve Takvim etkinlikleri izinlerine erişim izni verdiğini gösterir:

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

Google API'lerini çağırma

PHP

Aşağıdaki adımları tamamlayarak Google API'lerini çağırmak için erişim jetonunu kullanın:

  1. Yeni bir Google\Client nesnesine erişim jetonu uygulamanız gerekiyorsa (örneğin, erişim jetonunu bir kullanıcı oturumunda depoladıysanız) setAccessToken yöntemini kullanın:
    $client->setAccessToken($access_token);
  2. Çağırmak istediğiniz API için bir hizmet nesnesi oluşturun. Çağırmak istediğiniz API'nin oluşturucusuna yetkili bir Google\Client nesnesi sağlayarak hizmet nesnesi oluşturursunuz. Örneğin, Drive API'yi çağırmak için:
    $drive = new Google\Service\Drive($client);
  3. Hizmet nesnesi tarafından sağlanan arayüzü kullanarak API hizmetine istek gönderme Örneğin, kimliği doğrulanmış kullanıcının Google Drive'ındaki dosyaları listelemek için:
    $files = $drive->files->listFiles(array());

Python

Uygulamanız, erişim jetonu aldıktan sonra bu jetonu kullanarak belirli bir kullanıcı hesabı veya hizmet hesabı adına API isteklerini yetkilendirebilir. Çağırmak istediğiniz API için bir hizmet nesnesi oluşturmak üzere kullanıcıya özel yetkilendirme kimlik bilgilerini kullanın ve ardından yetkili API istekleri göndermek için bu nesneyi kullanın.

  1. Çağırmak istediğiniz API için bir hizmet nesnesi oluşturun. API'nin adı ve sürümü ile kullanıcı kimlik bilgilerini kullanarak googleapiclient.discovery kitaplığının build yöntemini çağırarak bir hizmet nesnesi oluşturursunuz: Örneğin, Drive API'nin 3. sürümünü çağırmak için:
    from googleapiclient.discovery import build
    
    drive = build('drive', 'v2', credentials=credentials)
  2. Hizmet nesnesi tarafından sağlanan arayüzü kullanarak API hizmetine istekte bulunun. Örneğin, kimliği doğrulanmış kullanıcının Google Drive'ındaki dosyaları listelemek için:
    files = drive.files().list().execute()

Ruby

Uygulamanız, erişim jetonu aldıktan sonra bu jetonu kullanarak belirli bir kullanıcı hesabı veya hizmet hesabı adına API istekleri gönderebilir. Çağırmak istediğiniz API için bir hizmet nesnesi oluşturmak üzere kullanıcıya özel yetkilendirme kimlik bilgilerini kullanın ve ardından yetkili API istekleri göndermek için bu nesneyi kullanın.

  1. Çağırmak istediğiniz API için bir hizmet nesnesi oluşturun. Örneğin, Drive API'nin 3. sürümünü çağırmak için:
    drive = Google::Apis::DriveV3::DriveService.new
  2. Hizmette kimlik bilgilerini ayarlayın:
    drive.authorization = credentials
  3. Hizmet nesnesi tarafından sağlanan arayüzü kullanarak API hizmetine istekte bulunun. Örneğin, kimliği doğrulanmış kullanıcının Google Drive'ındaki dosyaları listelemek için:
    files = drive.list_files

Alternatif olarak, bir yönteme options parametresi sağlanarak yöntem bazında yetkilendirme yapılabilir:

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

Node.js

Erişim jetonunu alıp OAuth2 nesnesine ayarladıktan sonra Google API'lerini çağırmak için nesneyi kullanın. Uygulamanız, belirli bir kullanıcı hesabı veya hizmet hesabı adına API isteklerini yetkilendirmek için bu jetonu kullanabilir. Çağırmak istediğiniz API için bir hizmet nesnesi oluşturun. Örneğin, aşağıdaki kod, kullanıcının Drive'ındaki dosya adlarını listelemek için Google Drive API'yi kullanır.

const { google } = require('googleapis');

// Example of using Google Drive API to list filenames in user's Drive.
const drive = google.drive('v3');
drive.files.list({
  auth: oauth2Client,
  pageSize: 10,
  fields: 'nextPageToken, files(id, name)',
}, (err1, res1) => {
  if (err1) return console.log('The API returned an error: ' + err1);
  const files = res1.data.files;
  if (files.length) {
    console.log('Files:');
    files.map((file) => {
      console.log(`${file.name} (${file.id})`);
    });
  } else {
    console.log('No files found.');
  }
});

HTTP/REST

Uygulamanız bir erişim jetonu aldıktan sonra, API'nin gerektirdiği erişim kapsamları verilmişse belirli bir kullanıcı hesabı adına Google API'sine çağrı yapmak için jetonu kullanabilirsiniz. Bunu yapmak için bir access_token sorgu parametresi veya bir Authorization HTTP üstbilgisi Bearer değeri ekleyerek erişim jetonunu API'ye gönderilen bir isteğe ekleyin. Mümkün olduğunda HTTP başlığı tercih edilir çünkü sorgu dizeleri sunucu günlüklerinde görünür. Çoğu durumda, Google API'lerine çağrılarınızı ayarlamak için bir istemci kitaplığı kullanabilirsiniz (örneğin, Drive Files API'yi çağırırken).

Tüm Google API'lerini deneyebilir ve kapsamlarını OAuth 2.0 Playground'da görüntüleyebilirsiniz.

HTTP GET örnekleri

Authorization: Bearer HTTP üst bilgisini kullanarak drive.files uç noktasına (Drive Files API) yapılan bir çağrı aşağıdaki gibi görünebilir. Kendi erişim jetonunuzu belirtmeniz gerektiğini unutmayın:

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

access_token sorgu dizesi parametresini kullanan kimliği doğrulanmış kullanıcı için aynı API'ye yapılan çağrı aşağıda verilmiştir:

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

curl örnek

Bu komutları curl komut satırı uygulamasıyla test edebilirsiniz. HTTP üstbilgisi seçeneğini (tercih edilen) kullanan bir örnek aşağıda verilmiştir:

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

Alternatif olarak sorgu dizesi parametresi seçeneğini de kullanabilirsiniz:

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

Eksiksiz örnek

Aşağıdaki örnekte, kullanıcı kimlik doğrulama işlemini tamamlayıp uygulamanın kullanıcının Drive meta verilerine erişmesine izin verdikten sonra kullanıcının Google Drive'ındaki dosyaların JSON biçimli bir listesi yazdırılır.

PHP

Bu örneği çalıştırmak için:

  1. API Console'da, yerel makinenin URL'sini yönlendirme URL'leri listesine ekleyin. Örneğin, http://localhost:8080 URL'sini ekleyin.
  2. Yeni bir dizin oluşturun ve bu dizine geçin. Örneğin:
    mkdir ~/php-oauth2-example
    cd ~/php-oauth2-example
  3. Composer'ı kullanarak PHP için Google API istemci kitaplığını yükleyin:
    composer require google/apiclient:^2.15.0
  4. Aşağıdaki içerikle index.php ve oauth2callback.php dosyalarını oluşturun.
  5. Örneği PHP'nin yerleşik test web sunucusuyla çalıştırın:
    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_secret.json');

// User granted permission as an access token is in the session.
if (isset($_SESSION['access_token']) && $_SESSION['access_token'])
{
  $client->setAccessToken($_SESSION['access_token']);
  
  // Check if user granted Drive permission
  if ($_SESSION['granted_scopes_dict']['Drive']) {
    echo "Drive feature is enabled.";
    echo "</br>";
    $drive = new Drive($client);
    $files = array();
    $response = $drive->files->listFiles(array());
    foreach ($response->files as $file) {
        echo "File: " . $file->name . " (" . $file->id . ")";
        echo "</br>";
    }
  } else {
    echo "Drive feature is NOT enabled.";
    echo "</br>";
  }

   // Check if user granted Calendar permission
  if ($_SESSION['granted_scopes_dict']['Calendar']) {
    echo "Calendar feature is enabled.";
    echo "</br>";
  } else {
    echo "Calendar feature is NOT enabled.";
    echo "</br>";
  }
}
else
{
  // Redirect users to outh2call.php which redirects users to Google OAuth 2.0
  $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();

// Required, call the setAuthConfig function to load authorization credentials from
// client_secret.json file.
$client->setAuthConfigFile('client_secret.json');
$client->setRedirectUri('http://' . $_SERVER['HTTP_HOST']. $_SERVER['PHP_SELF']);

// Required, to set the scope value, call the addScope function.
$client->addScope([Google\Service\Drive::DRIVE_METADATA_READONLY, Google\Service\Calendar::CALENDAR_READONLY]);

// Enable incremental authorization. Recommended as a best practice.
$client->setIncludeGrantedScopes(true);

// Recommended, 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");

// Generate a URL for authorization as it doesn't contain code and error
if (!isset($_GET['code']) && !isset($_GET['error']))
{
  // Generate and set state value
  $state = bin2hex(random_bytes(16));
  $client->setState($state);
  $_SESSION['state'] = $state;

  // Generate a url that asks permissions.
  $auth_url = $client->createAuthUrl();
  header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));
}

// User authorized the request and authorization code is returned to exchange access and
// refresh tokens.
if (isset($_GET['code']))
{
  // Check the state value
  if (!isset($_GET['state']) || $_GET['state'] !== $_SESSION['state']) {
    die('State mismatch. Possible CSRF attack.');
  }

  // Get access and refresh tokens (if access_type is offline)
  $token = $client->fetchAccessTokenWithAuthCode($_GET['code']);

  /** Save access and refresh token to the session variables.
    * ACTION ITEM: In a production app, you likely want to save the
    *              refresh token in a secure persistent storage instead. */
  $_SESSION['access_token'] = $token;
  $_SESSION['refresh_token'] = $client->getRefreshToken();
  
  // Space-separated string of granted scopes if it exists, otherwise null.
  $granted_scopes = $client->getOAuth2Service()->getGrantedScope();

  // Determine which scopes user granted and build a dictionary
  $granted_scopes_dict = [
    'Drive' => str_contains($granted_scopes, Google\Service\Drive::DRIVE_METADATA_READONLY),
    'Calendar' => str_contains($granted_scopes, Google\Service\Calendar::CALENDAR_READONLY)
  ];
  $_SESSION['granted_scopes_dict'] = $granted_scopes_dict;
  
  $redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . '/';
  header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}

// An error response e.g. error=access_denied
if (isset($_GET['error']))
{
  echo "Error: ". $_GET['error'];
}
?>

Python

Bu örnekte Flask çerçevesi kullanılmaktadır. Bu komut, http://localhost:8080 adresinde OAuth 2.0 akışını test etmenize olanak tanıyan bir web uygulaması çalıştırır. Bu URL'ye giderseniz beş bağlantı görürsünüz:

  • Call Drive API: Bu bağlantı, kullanıcıların izin vermesi durumunda örnek bir API isteği yürütmeye çalışan bir sayfaya yönlendirir. Gerekirse yetkilendirme akışını başlatır. İşlem başarılı olursa sayfada API yanıtı gösterilir.
  • Calendar API'yi çağırmak için örnek sayfa: Bu bağlantı, kullanıcılar izin verdiyse örnek bir Calendar API isteği yürütmeye çalışan örnek bir sayfaya yönlendirir. Gerekirse yetkilendirme akışını başlatır. İşlem başarılı olursa sayfada API yanıtı gösterilir.
  • Yetkilendirme akışını doğrudan test edin: Bu bağlantı, kullanıcıyı yetkilendirme akışına göndermeye çalışan bir sayfaya yönlendirir. Uygulama, kullanıcı adına yetkili API istekleri göndermek için izin ister.
  • Mevcut kimlik bilgilerini iptal etme: Bu bağlantı, kullanıcının uygulamaya daha önce verdiği izinleri iptal eden bir sayfaya yönlendirir.
  • Clear Flask session credentials (Flask oturumu kimlik bilgilerini temizle): Bu bağlantı, Flask oturumunda depolanan yetkilendirme kimlik bilgilerini temizler. Bu sayede, uygulamanıza daha önce izin vermiş bir kullanıcının yeni bir oturumda API isteği yürütmeye çalışması durumunda ne olacağını görebilirsiniz. Ayrıca, uygulamanıza verilen izinler kullanıcı tarafından iptal edildiyse ve uygulamanız iptal edilen bir erişim jetonuyla isteği yetkilendirmeye çalışıyorsa uygulamanızın alacağı API yanıtını görmenizi sağlar.
# -*- coding: utf-8 -*-

import os
import flask
import json
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"

# The OAuth 2.0 access scope allows for access to the
# authenticated user's account and requires requests to use an SSL connection.
SCOPES = ['https://www.googleapis.com/auth/drive.metadata.readonly',
          'https://www.googleapis.com/auth/calendar.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('/drive')
def drive_api_request():
  if 'credentials' not in flask.session:
    return flask.redirect('authorize')

  features = flask.session['features']

  if features['drive']:
    # Load client secrets from the server-side file.
    with open(CLIENT_SECRETS_FILE, 'r') as f:
        client_config = json.load(f)['web']

    # Load user-specific credentials from browser session storage.
    session_credentials = flask.session['credentials']

    # Reconstruct the credentials object.
    credentials = google.oauth2.credentials.Credentials(
        refresh_token=session_credentials.get('refresh_token'),
        scopes=session_credentials.get('granted_scopes'),
        token=session_credentials.get('token'),
        client_id=client_config.get('client_id'),
        client_secret=client_config.get('client_secret'),
        token_uri=client_config.get('token_uri'))

    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.
    flask.session['credentials'] = credentials_to_dict(credentials)

    return flask.jsonify(**files)
  else:
    # User didn't authorize read-only Drive activity permission.
    return '<p>Drive feature is not enabled.</p>'

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

  features = flask.session['features']

  if features['calendar']:
    # User authorized Calendar read permission.
    # Calling the APIs, etc.
    return ('<p>User granted the Google Calendar read permission. '+
            'This sample code does not include code to call Calendar</p>')
  else:
    # User didn't authorize Calendar read permission.
    # Update UX and application accordingly
    return '<p>Calendar feature is not enabled.</p>'

@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
  
  credentials = credentials_to_dict(credentials)
  flask.session['credentials'] = credentials

  # Check which scopes user granted
  features = check_granted_scopes(credentials)
  flask.session['features'] = features
  return flask.redirect('/')
  
@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.')

  # Load client secrets from the server-side file.
  with open(CLIENT_SECRETS_FILE, 'r') as f:
      client_config = json.load(f)['web']

  # Load user-specific credentials from the session.
  session_credentials = flask.session['credentials']

  # Reconstruct the credentials object.
  credentials = google.oauth2.credentials.Credentials(
      refresh_token=session_credentials.get('refresh_token'),
      scopes=session_credentials.get('granted_scopes'),
      token=session_credentials.get('token'),
      client_id=client_config.get('client_id'),
      client_secret=client_config.get('client_secret'),
      token_uri=client_config.get('token_uri'))

  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:
    # Clear the user's session credentials after successful revocation
    if 'credentials' in flask.session:
        del flask.session['credentials']
        del flask.session['features']
    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,
          'granted_scopes': credentials.granted_scopes}

def check_granted_scopes(credentials):
  features = {}
  if 'https://www.googleapis.com/auth/drive.metadata.readonly' in credentials['granted_scopes']:
    features['drive'] = True
  else:
    features['drive'] = False

  if 'https://www.googleapis.com/auth/calendar.readonly' in credentials['granted_scopes']:
    features['calendar'] = True
  else:
    features['calendar'] = False

  return features

def print_index_table():
  return ('<table>' + 
          '<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="/drive">Call Drive API directly</a></td>' +
          '<td> Use stored credentials to call the API, you still might not be prompted to reauthorize ' +
          '    the application.</td></tr>' +
          '<tr><td><a href="/calendar">Call Calendar API directly</a></td>' +
          '<td> Use stored credentials to call the API, 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="/authorize">authorize</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'

  # This disables the requested scopes and granted scopes check.
  # If users only grant partial request, the warning would not be thrown.
  os.environ['OAUTHLIB_RELAX_TOKEN_SCOPE'] = '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

Bu örnekte Sinatra çerçevesi kullanılmaktadır.

require 'googleauth'
require 'googleauth/web_user_authorizer'
require 'googleauth/stores/redis_token_store'

require 'google/apis/drive_v3'
require 'google/apis/calendar_v3'

require 'sinatra'

configure do
  enable :sessions

  # Required, call the from_file method to retrieve the client ID from a
  # client_secret.json file.
  set :client_id, Google::Auth::ClientId.from_file('/path/to/client_secret.json')

  # Required, scope value
  # Access scopes for two non-Sign-In scopes: Read-only Drive activity and Google Calendar.
  scope = ['Google::Apis::DriveV3::AUTH_DRIVE_METADATA_READONLY',
           'Google::Apis::CalendarV3::AUTH_CALENDAR_READONLY']

  # Required, Authorizers require a storage instance to manage long term persistence of
  # access and refresh tokens.
  set :token_store, Google::Auth::Stores::RedisTokenStore.new(redis: Redis.new)

  # Required, 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.
  set :callback_uri, '/oauth2callback'

  # To use OAuth2 authentication, we need access to a CLIENT_ID, CLIENT_SECRET, AND REDIRECT_URI
  # from the client_secret.json file. To get these credentials for your application, visit
  # https://console.cloud.google.com/apis/credentials.
  set :authorizer, Google::Auth::WebUserAuthorizer.new(settings.client_id, settings.scope,
                          settings.token_store, callback_uri: settings.callback_uri)
end

get '/' do
  # NOTE: Assumes the user is already authenticated to the app
  user_id = request.session['user_id']

  # Fetch stored credentials for the user from the given request session.
  # nil if none present
  credentials = settings.authorizer.get_credentials(user_id, request)

  if credentials.nil?
    # Generate a url that asks the user to authorize requested scope(s).
    # Then, redirect user to the url.
    redirect settings.authorizer.get_authorization_url(request: request)
  end
  
  # User authorized the request. Now, check which scopes were granted.
  if credentials.scope.include?(Google::Apis::DriveV3::AUTH_DRIVE_METADATA_READONLY)
    # User authorized read-only Drive activity permission.
    # Example of using Google Drive API to list filenames in user's Drive.
    drive = Google::Apis::DriveV3::DriveService.new
    files = drive.list_files(options: { authorization: credentials })
    "<pre>#{JSON.pretty_generate(files.to_h)}</pre>"
  else
    # User didn't authorize read-only Drive activity permission.
    # Update UX and application accordingly
  end

  # Check if user authorized Calendar read permission.
  if credentials.scope.include?(Google::Apis::CalendarV3::AUTH_CALENDAR_READONLY)
    # User authorized Calendar read permission.
    # Calling the APIs, etc.
  else
    # User didn't authorize Calendar read permission.
    # Update UX and application accordingly
  end
end

# Receive the callback from Google's OAuth 2.0 server.
get '/oauth2callback' do
  # Handle the result of the oauth callback. Defers the exchange of the code by
  # temporarily stashing the results in the user's session.
  target_url = Google::Auth::WebUserAuthorizer.handle_auth_callback_deferred(request)
  redirect target_url
end

Node.js

Bu örneği çalıştırmak için:

  1. API Console'da, yerel makinenin URL'sini yönlendirme URL'leri listesine ekleyin. Örneğin, http://localhost URL'sini ekleyin.
  2. Node.js'nin bakım LTS, etkin LTS veya güncel sürümünün yüklü olduğundan emin olun.
  3. Yeni bir dizin oluşturun ve bu dizine geçin. Örneğin:
    mkdir ~/nodejs-oauth2-example
    cd ~/nodejs-oauth2-example
  4. npm kullanarak Node.js için Google API istemci kitaplığını yükleyin:
    npm install googleapis
  5. Aşağıdaki içeriğe sahip main.js dosyalarını oluşturun.
  6. Örneği çalıştırın:
    node .\main.js

main.js

const http = require('http');
const https = require('https');
const url = require('url');
const { google } = require('googleapis');
const crypto = require('crypto');
const express = require('express');
const session = require('express-session');

/**
 * To use OAuth2 authentication, we need access to a CLIENT_ID, CLIENT_SECRET, AND REDIRECT_URI.
 * To get these credentials for your application, visit
 * https://console.cloud.google.com/apis/credentials.
 */
const oauth2Client = new google.auth.OAuth2(
  YOUR_CLIENT_ID,
  YOUR_CLIENT_SECRET,
  YOUR_REDIRECT_URL
);

// Access scopes for two non-Sign-In scopes: Read-only Drive activity and Google Calendar.
const scopes = [
  'https://www.googleapis.com/auth/drive.metadata.readonly',
  'https://www.googleapis.com/auth/calendar.readonly'
];

/* Global variable that stores user credential in this code example.
 * ACTION ITEM for developers:
 *   Store user's refresh token in your data store if
 *   incorporating this code into your real app.
 *   For more information on handling refresh tokens,
 *   see https://github.com/googleapis/google-api-nodejs-client#handling-refresh-tokens
 */
let userCredential = null;

async function main() {
  const app = express();

  app.use(session({
    secret: 'your_secure_secret_key', // Replace with a strong secret
    resave: false,
    saveUninitialized: false,
  }));

  // Example on redirecting user to Google's OAuth 2.0 server.
  app.get('/', async (req, res) => {
    // Generate a secure random state value.
    const state = crypto.randomBytes(32).toString('hex');
    // Store state in the session
    req.session.state = state;

    // Generate a url that asks permissions for the Drive activity and Google Calendar scope
    const authorizationUrl = oauth2Client.generateAuthUrl({
      // 'online' (default) or 'offline' (gets refresh_token)
      access_type: 'offline',
      /** Pass in the scopes array defined above.
        * Alternatively, if only one scope is needed, you can pass a scope URL as a string */
      scope: scopes,
      // Enable incremental authorization. Recommended as a best practice.
      include_granted_scopes: true,
      // Include the state parameter to reduce the risk of CSRF attacks.
      state: state
    });

    res.redirect(authorizationUrl);
  });

  // Receive the callback from Google's OAuth 2.0 server.
  app.get('/oauth2callback', async (req, res) => {
    // Handle the OAuth 2.0 server response
    let q = url.parse(req.url, true).query;

    if (q.error) { // An error response e.g. error=access_denied
      console.log('Error:' + q.error);
    } else if (q.state !== req.session.state) { //check state value
      console.log('State mismatch. Possible CSRF attack');
      res.end('State mismatch. Possible CSRF attack');
    } else { // Get access and refresh tokens (if access_type is offline)
      let { tokens } = await oauth2Client.getToken(q.code);
      oauth2Client.setCredentials(tokens);

      /** Save credential to the global variable in case access token was refreshed.
        * ACTION ITEM: In a production app, you likely want to save the refresh token
        *              in a secure persistent database instead. */
      userCredential = tokens;
      
      // User authorized the request. Now, check which scopes were granted.
      if (tokens.scope.includes('https://www.googleapis.com/auth/drive.metadata.readonly'))
      {
        // User authorized read-only Drive activity permission.
        // Example of using Google Drive API to list filenames in user's Drive.
        const drive = google.drive('v3');
        drive.files.list({
          auth: oauth2Client,
          pageSize: 10,
          fields: 'nextPageToken, files(id, name)',
        }, (err1, res1) => {
          if (err1) return console.log('The API returned an error: ' + err1);
          const files = res1.data.files;
          if (files.length) {
            console.log('Files:');
            files.map((file) => {
              console.log(`${file.name} (${file.id})`);
            });
          } else {
            console.log('No files found.');
          }
        });
      }
      else
      {
        // User didn't authorize read-only Drive activity permission.
        // Update UX and application accordingly
      }

      // Check if user authorized Calendar read permission.
      if (tokens.scope.includes('https://www.googleapis.com/auth/calendar.readonly'))
      {
        // User authorized Calendar read permission.
        // Calling the APIs, etc.
      }
      else
      {
        // User didn't authorize Calendar read permission.
        // Update UX and application accordingly
      }
    }
  });

  // Example on revoking a token
  app.get('/revoke', async (req, res) => {
    // Build the string for the POST request
    let postData = "token=" + userCredential.access_token;

    // Options for POST request to Google's OAuth 2.0 server to revoke a token
    let postOptions = {
      host: 'oauth2.googleapis.com',
      port: '443',
      path: '/revoke',
      method: 'POST',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
        'Content-Length': Buffer.byteLength(postData)
      }
    };

    // Set up the request
    const postReq = https.request(postOptions, function (res) {
      res.setEncoding('utf8');
      res.on('data', d => {
        console.log('Response: ' + d);
      });
    });

    postReq.on('error', error => {
      console.log(error)
    });

    // Post the request with data
    postReq.write(postData);
    postReq.end();
  });


  const server = http.createServer(app);
  server.listen(8080);
}
main().catch(console.error);

HTTP/REST

Bu Python örneğinde, OAuth 2.0 web akışını göstermek için Flask çerçevesi ve Requests kitaplığı kullanılmaktadır. Bu akış için Python için Google API İstemci Kitaplığı'nı kullanmanızı öneririz. (Python sekmesindeki örnekte istemci kitaplığı kullanılır.)

import json
import flask
import requests

app = flask.Flask(__name__)

# To get these credentials (CLIENT_ID CLIENT_SECRET) and for your application, visit
# https://console.cloud.google.com/apis/credentials.
CLIENT_ID = '123456789.apps.googleusercontent.com'
CLIENT_SECRET = 'abc123'  # Read from a file or environmental variable in a real app

# Access scopes for two non-Sign-In scopes: Read-only Drive activity and Google Calendar.
SCOPE = 'https://www.googleapis.com/auth/drive.metadata.readonly https://www.googleapis.com/auth/calendar.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.
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: 
    # User authorized the request. Now, check which scopes were granted.
    if 'https://www.googleapis.com/auth/drive.metadata.readonly' in credentials['scope']:
      # User authorized read-only Drive activity permission.
      # Example of using Google Drive API to list filenames in user's Drive.
      headers = {'Authorization': 'Bearer {}'.format(credentials['access_token'])}
      req_uri = 'https://www.googleapis.com/drive/v2/files'
      r = requests.get(req_uri, headers=headers).text
    else:
      # User didn't authorize read-only Drive activity permission.
      # Update UX and application accordingly
      r = 'User did not authorize Drive permission.'

    # Check if user authorized Calendar read permission.
    if 'https://www.googleapis.com/auth/calendar.readonly' in credentials['scope']:
      # User authorized Calendar read permission.
      # Calling the APIs, etc.
      r += 'User authorized Calendar permission.'
    else:
      # User didn't authorize Calendar read permission.
      # Update UX and application accordingly
      r += 'User did not authorize Calendar permission.'

  return r

@app.route('/oauth2callback')
def oauth2callback():
  if 'code' not in flask.request.args:
    state = str(uuid.uuid4())
    flask.session['state'] = state
    # Generate a url that asks permissions for the Drive activity
    # and Google Calendar scope. Then, redirect user to the url.
    auth_uri = ('https://accounts.google.com/o/oauth2/v2/auth?response_type=code'
                '&client_id={}&redirect_uri={}&scope={}&state={}').format(CLIENT_ID, REDIRECT_URI,
                                                                          SCOPE, state)
    return flask.redirect(auth_uri)
  else:
    if 'state' not in flask.request.args or flask.request.args['state'] != flask.session['state']:
      return 'State mismatch. Possible CSRF attack.', 400

    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'}

    # Exchange authorization code for access and refresh tokens (if access_type is offline)
    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()

Yönlendirme URI'si doğrulama kuralları

Google, geliştiricilerin uygulamalarını güvende tutmalarına yardımcı olmak için yönlendirme URI'lerine aşağıdaki doğrulama kurallarını uygular. Yönlendirme URI'leriniz bu kurallara uymalıdır. Bu kurallarda kullanılan alan, ana makine, yol, sorgu, şema ve kullanıcı bilgileri tanımları için RFC 3986 bölüm 3'e bakın.

Doğrulama kuralları
Şema

Yönlendirme URI'ları düz HTTP değil, HTTPS şemasını kullanmalıdır. Localhost URI'leri (localhost IP adresi URI'leri dahil) bu kuraldan muaftır.

Düzenleyen

Ana makineler ham IP adresleri olamaz. Localhost IP adresleri bu kuraldan muaftır.

Alan
  • Ana makine TLD'leri (üst düzey alanlar) herkese açık son ek listesinde yer almalıdır.
  • Ana makine alan adları “googleusercontent.com” olamaz.
  • Yönlendirme URI'leri, uygulama alanın sahibi olmadığı sürece URL kısaltıcı alanları (ör. goo.gl) içeremez. Ayrıca, kısaltıcı alan adına sahip bir uygulama bu alan adına yönlendirme yapmayı seçerse bu yönlendirme URI'sinin yolunda “/google-callback/” bulunmalı veya URI “/google-callback” ile bitmelidir.
  • Userinfo

    Yönlendirme URI'leri, userinfo alt bileşenini içeremez.

    Yol

    Yönlendirme URI'leri, “/..” veya “\..” ya da bunların URL kodlaması ile temsil edilen bir yol geçişi (dizin geri izleme olarak da bilinir) içeremez.

    Sorgu

    Yönlendirme URI'leri açık yönlendirmeler içeremez.

    Fragment

    Yönlendirme URI'leri, parça bileşeni içeremez.

    Karakterler Yönlendirme URI'leri aşağıdakiler de dahil olmak üzere belirli karakterleri içeremez:
    • Joker karakterler ('*')
    • Yazdırılamayan ASCII karakterleri
    • Geçersiz yüzde kodlamaları (yüzde işaretinden sonra iki onaltılık basamak içeren URL kodlama biçimine uymayan tüm yüzde kodlamaları)
    • Boş karakterler (kodlanmış bir NULL karakter, ör. %00, %C0%80)

    Artımlı yetkilendirme

    OAuth 2.0 protokolünde uygulamanız, kapsamlarla tanımlanan kaynaklara erişim için yetkilendirme ister. Kaynaklar için yetkilendirmeyi ihtiyaç duyduğunuz anda istemek, kullanıcı deneyimi açısından en iyi uygulama olarak kabul edilir. Bu uygulamayı etkinleştirmek için Google'ın yetkilendirme sunucusu, artımlı yetkilendirmeyi destekler. Bu özellik, kapsamları gerektiğinde istemenize olanak tanır ve kullanıcı yeni kapsam için izin verirse kullanıcının projeye verdiği tüm kapsamları içeren bir jetonla değiştirilebilecek bir yetkilendirme kodu döndürür.

    Örneğin, kullanıcıların müzik parçalarını örneklemesine ve miksler oluşturmasına olanak tanıyan bir uygulamanın, oturum açma sırasında çok az kaynağa ihtiyacı olabilir. Belki de oturum açan kişinin adından başka bir şeye ihtiyacı yoktur. Ancak tamamlanan bir miksi kaydetmek için Google Drive'larına erişim gerekir. Çoğu kullanıcı, Google Drive'larına erişim izninin yalnızca uygulamanın gerçekten ihtiyaç duyduğu anda istenmesini doğal karşılar.

    Bu durumda uygulama, oturum açma sırasında temel oturum açma işlemini gerçekleştirmek için openid ve profile kapsamlarını, daha sonra ise bir karışımı kaydetmek için ilk istek sırasında https://www.googleapis.com/auth/drive.file kapsamını isteyebilir.

    Artımlı yetkilendirmeyi uygulamak için erişim jetonu isteme ile ilgili normal akışı tamamlarsınız ancak yetkilendirme isteğinin daha önce verilen kapsamları içerdiğinden emin olmanız gerekir. Bu yaklaşım, uygulamanızın birden fazla erişim jetonunu yönetme ihtiyacını ortadan kaldırır.

    Kademeli yetkilendirmeden alınan erişim jetonları için aşağıdaki kurallar geçerlidir:

    • Jeton, yeni ve birleştirilmiş yetkilendirmeye dahil edilen kapsamlardan herhangi birine karşılık gelen kaynaklara erişmek için kullanılabilir.
    • Erişim jetonu almak üzere birleştirilmiş yetkilendirme için yenileme jetonunu kullandığınızda erişim jetonu, birleştirilmiş yetkilendirmeyi temsil eder ve yanıta dahil edilen scope değerlerinden herhangi biri için kullanılabilir.
    • Birleşik yetkilendirme, farklı istemcilerden istenmiş olsa bile kullanıcının API projesine verdiği tüm kapsamları içerir. Örneğin, bir kullanıcı bir uygulamanın masaüstü istemcisini kullanarak bir kapsama erişim izni verdikten sonra aynı uygulamaya mobil uygulama istemcisi aracılığıyla başka bir kapsam için izin verirse birleştirilmiş yetkilendirme her iki kapsamı da içerir.
    • Birleşik bir yetkilendirmeyi temsil eden bir jetonu iptal ederseniz ilişkili kullanıcı adına bu yetkilendirmenin tüm kapsamlarına erişim aynı anda iptal edilir.

    1. Adım: Yetkilendirmeyi ayarlayın Google'ın OAuth 2.0 sunucusuna yönlendirin bölümündeki dile özgü kod örneklerinin tümünde artımlı yetkilendirme kullanılır. Aşağıdaki kod örneklerinde, artımlı yetkilendirmeyi kullanmak için eklemeniz gereken kod da gösterilmektedir.

    PHP

    $client->setIncludeGrantedScopes(true);

    Python

    Python'da, yetkilendirme isteğinin daha önce verilen kapsamları içerdiğinden emin olmak için include_granted_scopes anahtar kelime bağımsız değişkenini true olarak ayarlayın. Aşağıdaki örnekte gösterildiği gibi, include_granted_scopes, ayarladığınız tek anahtar kelime bağımsız değişkeni olmayabilir.

    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"}
    )

    Node.js

    const authorizationUrl = oauth2Client.generateAuthUrl({
      // 'online' (default) or 'offline' (gets refresh_token)
      access_type: 'offline',
      /** Pass in the scopes array defined above.
        * Alternatively, if only one scope is needed, you can pass a scope URL as a string */
      scope: scopes,
      // Enable incremental authorization. Recommended as a best practice.
      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.metadata.readonly%20https%3A//www.googleapis.com/auth/calendar.readonly&
      redirect_uri=https%3A//developers.google.com/oauthplayground&
      prompt=consent&
      include_granted_scopes=true

    Erişim jetonunu yenileme (çevrimdışı erişim)

    Erişim jetonlarının süresi belirli aralıklarla dolar ve ilgili API isteği için geçersiz kimlik bilgileri haline gelir. Jetonla ilişkili kapsamlara çevrimdışı erişim istediyseniz kullanıcıdan izin istemeden (kullanıcı mevcut olmadığında bile) erişim jetonunu yenileyebilirsiniz.

    Çevrimdışı erişim isteğinde bulunmak, kullanıcı mevcut olmadığında bir Google API'sine erişmesi gereken tüm uygulamalar için zorunludur. Örneğin, yedekleme hizmetleri gerçekleştiren veya önceden belirlenmiş zamanlarda işlem yürüten bir uygulamanın, kullanıcı mevcut olmadığında erişim jetonunu yenileyebilmesi gerekir. Varsayılan erişim stili online olarak adlandırılır.

    Sunucu tarafı web uygulamaları, yüklü uygulamalar ve cihazlar, yetkilendirme işlemi sırasında yenileme jetonları alır. Yenileme jetonları genellikle istemci tarafı (JavaScript) web uygulamalarında kullanılmaz.

    PHP

    Uygulamanızın bir Google API'sine çevrimdışı erişmesi gerekiyorsa API istemcisinin erişim türünü offline olarak ayarlayın:

    $client->setAccessType("offline");

    Kullanıcı, istenen kapsamlara çevrimdışı erişim izni verdikten sonra, kullanıcı çevrimdışıyken Google API'lerine kullanıcı adına erişmek için API istemcisini kullanmaya devam edebilirsiniz. İstemci nesnesi, erişim jetonunu gerektiği şekilde yeniler.

    Python

    Python'da, kullanıcıdan tekrar izin istemek zorunda kalmadan erişim jetonunu yenileyebilmek için access_type anahtar kelime bağımsız değişkenini offline olarak ayarlayın. Aşağıdaki örnekte gösterildiği gibi, access_type, ayarladığınız tek anahtar kelime bağımsız değişkeni olmayabilir.

    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')

    Kullanıcı, istenen kapsamlara çevrimdışı erişim izni verdikten sonra, kullanıcı çevrimdışıyken Google API'lerine kullanıcı adına erişmek için API istemcisini kullanmaya devam edebilirsiniz. İstemci nesnesi, erişim jetonunu gerektiği şekilde yeniler.

    Ruby

    Uygulamanızın bir Google API'sine çevrimdışı erişmesi gerekiyorsa API istemcisinin erişim türünü offline olarak ayarlayın:

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

    Kullanıcı, istenen kapsamlara çevrimdışı erişim izni verdikten sonra, kullanıcı çevrimdışıyken Google API'lerine kullanıcı adına erişmek için API istemcisini kullanmaya devam edebilirsiniz. İstemci nesnesi, erişim jetonunu gerektiği şekilde yeniler.

    Node.js

    Uygulamanızın bir Google API'sine çevrimdışı erişmesi gerekiyorsa API istemcisinin erişim türünü offline olarak ayarlayın:

    const authorizationUrl = oauth2Client.generateAuthUrl({
      // 'online' (default) or 'offline' (gets refresh_token)
      access_type: 'offline',
      /** Pass in the scopes array defined above.
        * Alternatively, if only one scope is needed, you can pass a scope URL as a string */
      scope: scopes,
      // Enable incremental authorization. Recommended as a best practice.
      include_granted_scopes: true
    });

    Kullanıcı, istenen kapsamlara çevrimdışı erişim izni verdikten sonra, kullanıcı çevrimdışıyken Google API'lerine kullanıcı adına erişmek için API istemcisini kullanmaya devam edebilirsiniz. İstemci nesnesi, erişim jetonunu gerektiği şekilde yeniler.

    Erişim jetonlarının süresi dolduğunda Bu kitaplık, süresi dolmak üzere olan erişim jetonunun yerine yeni bir erişim jetonu almak için otomatik olarak yenileme jetonu kullanır. Her zaman en güncel jetonları sakladığınızdan emin olmanın kolay bir yolu, jeton etkinliğini kullanmaktır:

    oauth2Client.on('tokens', (tokens) => {
      if (tokens.refresh_token) {
        // store the refresh_token in your secure persistent database
        console.log(tokens.refresh_token);
      }
      console.log(tokens.access_token);
    });

    Bu jeton etkinliği yalnızca ilk yetkilendirmede gerçekleşir ve yenileme jetonunu almak için generateAuthUrl yöntemini çağırırken access_type parametresini offline olarak ayarlamanız gerekir. Yenileme jetonu almak için uygun kısıtlamaları ayarlamadan uygulamanıza gerekli izinleri verdiyseniz yeni bir yenileme jetonu almak için uygulamayı yeniden yetkilendirmeniz gerekir.

    refresh_token değerini daha sonra ayarlamak için setCredentials yöntemini kullanabilirsiniz:

    oauth2Client.setCredentials({
      refresh_token: `STORED_REFRESH_TOKEN`
    });

    İstemci bir yenileme jetonuna sahip olduğunda, erişim jetonları API'ye yapılan bir sonraki çağrıda otomatik olarak alınır ve yenilenir.

    HTTP/REST

    Uygulamanız, erişim jetonunu yenilemek için Google'ın yetkilendirme sunucusuna (https://oauth2.googleapis.com/token) istek gövdesinde aşağıdaki parametreleri içeren bir HTTPS POST isteği gönderir:

    Ad Değer
    client_id API Konsolu'ndan alınan istemci kimliği.
    client_secret İsteğe bağlı

    API Konsolu'ndan alınan istemci gizli anahtarı.

    grant_type OAuth 2.0 spesifikasyonunda tanımlandığı gibi, bu alanın değeri refresh_token olarak ayarlanmalıdır.
    refresh_token Yetkilendirme kodu değiş tokuşundan döndürülen yenileme jetonu.

    DPoP kullanımı isteğe bağlı olsa da daha fazla güvenlik için önerilir. DPoP'u yenileme jetonuyla kullanmak için uygulamanızın, jeton uç noktasına yapılan her istek için yeni ve benzersiz bir DPoP kanıtı JWT'si oluşturması gerekir. Bu kanıt, ilk yetkilendirme kodu değişimi sırasında kullanılan özel anahtarla imzalanmalıdır. Uygulamanız, kanıtı HTTP istek başlığı olarak ekler.

    Başlık Zorunlu Açıklama
    DPoP İsteğe bağlı DPoP kanıtı, özel anahtarın sahipliğini kanıtlayan bir JWT'dir. Bu bir parametre değil, başlıktır. Sağlanırsa döndürülen jetonlar bu anahtara bağlanır. Her istek için yeni ve benzersiz bir kanıt oluşturulmalı ve istekle eşleşen htm (HTTP yöntemi) ve htu (HTTP URI) taleplerini içermelidir.

    Aşağıdaki snippet'te örnek bir istek gösterilmektedir:

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

    DPoP'u yenileme jetonuyla kullanmak için istek için yeni ve benzersiz bir DPoP kanıtı JWT'si oluşturmanız gerekir. Anahtar çiftini oluşturma ve JWT'yi oluşturma ile ilgili adım adım talimatlar için DPoP kanıtı oluşturma bölümüne bakın.

    Başarılı bir değişim, yeni bir erişim jetonu içeren 200 OK yanıtıyla belirtilir. DPoP kullanıldığında token_type, Bearer olur. Başarılı bir yanıt, yenileme jetonu için DPoP kanıtının kabul edildiğini onaylar. Google, yanıtta yeni bir DPoP-Nonce HTTP başlığı da döndürebilir. Döndürülürse istemciniz bu tek seferlik rastgele sayıyı önbelleğe almalı ve sonraki isteklerde DPoP kanıtının nonce talebine dahil etmelidir.

    DPoP başlığı eksik veya geçersizse ya da yanlış bir anahtar kullanıyorsa başarısız değişim gerçekleşir. Belirli DPoP hata kodları ve tek seferlik rastgele sayıların işlenmesiyle ilgili ayrıntılar için Başarısız değişim bölümüne bakın.

    Aşağıdaki snippet'te, DPoP kullanıldığında başarılı bir yanıt başlığı ve gövdesi örneği gösterilmektedir:

    HTTP/1.1 200 OK
    Content-Type: application/json; charset=utf-8
    DPoP-Nonce: AN3XwJjZsjnb0ZuWkRlek8QU7wY-Zhf-5IP6tO0tORz0KgtDT1Bo8FX-w4nz3r5lnepI
    
    {
      "access_token": "1/fFAGRNJru1FTz70BzhT3Zg",
      "expires_in": 3920,
      "scope": "https://www.googleapis.com/auth/drive.metadata.readonly https://www.googleapis.com/auth/calendar.readonly",
      "token_type": "Bearer"
    }

    Verilecek yenileme jetonlarının sayısıyla ilgili sınırlamalar olduğunu unutmayın. Bu sınırlamalardan biri istemci/kullanıcı kombinasyonu başına, diğeri ise tüm istemciler genelinde kullanıcı başınadır. Yenileme jetonlarını uzun süreli depolama alanına kaydetmeniz ve geçerli oldukları sürece kullanmaya devam etmeniz gerekir. Uygulamanız çok fazla yenileme jetonu isterse bu sınırlara takılabilir. Bu durumda eski yenileme jetonları çalışmayı durdurur.

    Jeton iptali

    Bazı durumlarda kullanıcılar bir uygulamaya verilen erişimi iptal etmek isteyebilir. Kullanıcı, Hesap Ayarları'nı ziyaret ederek erişimi iptal edebilir. Daha fazla bilgi için Hesabınıza erişimi olan üçüncü taraf siteleri ve uygulamaları destek dokümanındaki Site veya uygulama erişimini kaldırma bölümüne bakın.

    Bir uygulamanın, kendisine verilen erişimi programatik olarak iptal etmesi de mümkündür. Programatik iptal; kullanıcının abonelikten çıktığı, bir uygulamayı kaldırdığı veya bir uygulama için gereken API kaynaklarının önemli ölçüde değiştiği durumlarda önemlidir. Başka bir deyişle, kaldırma işleminin bir parçası olarak, uygulamaya daha önce verilen izinlerin kaldırıldığından emin olmak için bir API isteği gönderilebilir.

    PHP

    Bir jetonu programatik olarak iptal etmek için revokeToken() yöntemini çağırın:

    $client->revokeToken();

    Python

    Bir jetonu programatik olarak iptal etmek için https://oauth2.googleapis.com/revoke adresine, jetonu parametre olarak içeren ve Content-Type başlığını ayarlayan bir istek gönderin:

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

    Ruby

    Bir jetonu programatik olarak iptal etmek için oauth2.revoke uç noktasına bir HTTP isteği gönderin:

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

    Jeton, erişim jetonu veya yenileme jetonu olabilir. Jeton bir erişim jetonuysa ve karşılık gelen bir yenileme jetonu varsa yenileme jetonu da iptal edilir.

    İptal işlemi başarıyla tamamlanırsa yanıtın durum kodu 200 olur. Hata koşulları için hata koduyla birlikte 400 durum kodu döndürülür.

    Node.js

    Bir jetonu programatik olarak iptal etmek için /revoke uç noktasına bir HTTPS POST isteği gönderin:

    const https = require('https');
    
    // Build the string for the POST request
    let postData = "token=" + userCredential.access_token;
    
    // Options for POST request to Google's OAuth 2.0 server to revoke a token
    let postOptions = {
      host: 'oauth2.googleapis.com',
      port: '443',
      path: '/revoke',
      method: 'POST',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
        'Content-Length': Buffer.byteLength(postData)
      }
    };
    
    // Set up the request
    const postReq = https.request(postOptions, function (res) {
      res.setEncoding('utf8');
      res.on('data', d => {
        console.log('Response: ' + d);
      });
    });
    
    postReq.on('error', error => {
      console.log(error)
    });
    
    // Post the request with data
    postReq.write(postData);
    postReq.end();

    Jeton parametresi, erişim jetonu veya yenileme jetonu olabilir. Jeton bir erişim jetonuysa ve karşılık gelen bir yenileme jetonu varsa yenileme jetonu da iptal edilir.

    İptal işlemi başarıyla tamamlanırsa yanıtın durum kodu 200 olur. Hata koşulları için hata koduyla birlikte 400 durum kodu döndürülür.

    HTTP/REST

    Bir jetonu programatik olarak iptal etmek için uygulamanız https://oauth2.googleapis.com/revoke adresine istek gönderir ve jetonu parametre olarak ekler:

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

    Jeton, erişim jetonu veya yenileme jetonu olabilir. Jeton bir erişim jetonuysa ve karşılık gelen bir yenileme jetonu varsa yenileme jetonu da iptal edilir.

    İptal işlemi başarıyla işlenirse yanıtın HTTP durum kodu 200 olur. Hata koşulları için hata koduyla birlikte bir HTTP durum kodu 400 döndürülür.

    Zamana dayalı erişim

    Zamana dayalı erişim, kullanıcıların bir işlemi tamamlamak için uygulamanıza sınırlı bir süre boyunca verilerine erişim izni vermesine olanak tanır. Zaman tabanlı erişim, izin akışı sırasında belirli Google ürünlerinde kullanılabilir. Bu sayede kullanıcılar sınırlı bir süre için erişim izni verebilir. Verilerin tek seferlik aktarımını sağlayan Data Portability API buna örnek olarak verilebilir.

    Kullanıcı, uygulamanıza zamana dayalı erişim izni verdiğinde yenileme jetonunun süresi belirtilen sürenin sonunda dolar. Yenileme jetonlarının belirli durumlarda daha erken geçersiz kılınabileceğini unutmayın. Ayrıntılar için bu durumlara bakın. Yetkilendirme kodu değişimi yanıtında döndürülen refresh_token_expires_in alanı, bu gibi durumlarda yenileme jetonunun süresi dolana kadar kalan süreyi gösterir.

    Hesaplar Arası Koruma'yı uygulama

    Kullanıcılarınızın hesaplarını korumak için atmanız gereken ek bir adım, Google'ın Hesaplar Arası Koruma Hizmeti'nden yararlanarak Hesaplar Arası Koruma'yı uygulamaktır. Bu hizmet, kullanıcı hesabındaki önemli değişiklikler hakkında uygulamanıza bilgi veren güvenlik etkinliği bildirimlerine abone olmanızı sağlar. Ardından, etkinliklere nasıl yanıt vereceğinize karar vermek için bu bilgileri kullanarak harekete geçin.

    Google'ın Hesaplar Arası Koruma hizmeti tarafından uygulamanıza gönderilen etkinlik türlerine örnek olarak şunlar verilebilir:

    • https://schemas.openid.net/secevent/risc/event-type/sessions-revoked
    • https://schemas.openid.net/secevent/oauth/event-type/token-revoked
    • https://schemas.openid.net/secevent/risc/event-type/account-disabled

    Hesaplar Arası Koruma'yı nasıl uygulayacağınız hakkında daha fazla bilgi ve mevcut etkinliklerin tam listesi için Kullanıcı hesaplarını Hesaplar Arası Koruma ile koruma sayfasını inceleyin.