استفاده از OAuth 2.0 برای برنامه‌های سرور وب

این سند توضیح می‌دهد که برنامه‌های سرور وب چگونه از «کتابخانه‌های کارخواه Google API» یا نقطه‌های پایانی Google OAuth 2.0 برای پیاده‌سازی مجوز OAuth 2.0 برای دسترسی به Google APIs استفاده می‌کنند.

‫OAuth 2.0 به کاربران اجازه می‌دهد داده‌های خاصی را با برنامه‌ای هم‌رسانی کنند و درعین‌حال نام‌های کاربری، گذرواژه‌ها، و اطلاعات دیگرشان را خصوصی نگه دارند. برای مثال، یک برنامه می‌تواند از OAuth 2.0 برای دریافت اجازه از کاربران برای ذخیره فایل‌ها در Google Drive آن‌ها استفاده کند.

این جریان OAuth 2.0 به‌طور خاص برای صدور مجوز کاربر است. این جریان برای برنامه‌هایی طراحی شده است که می‌توانند اطلاعات محرمانه را ذخیره کنند و وضعیت را حفظ کنند. یک برنامه کارساز وب که به‌درستی مجوز گرفته باشد می‌تواند درحالی‌که کاربر با برنامه تعامل دارد یا پس‌از اینکه کاربر برنامه را ترک کرد، به میانای برنامه‌سازی کاربردی دسترسی پیدا کند.

برنامه‌های کارساز وب اغلب از حساب‌های سرویس نیز برای مجاز کردن درخواست‌های API استفاده می‌کنند، به‌ویژه هنگام فراخوانی Cloud APIs برای دسترسی به داده‌های مبتنی بر پروژه به‌جای داده‌های مختص کاربر. برنامه‌های کارساز وب می‌توانند از حساب‌های خدمات همراه با مجوز کاربر استفاده کنند.

کتابخانه‌های مشتری

نمونه‌های مختص زبان در این صفحه از کتابخانه‌های کارخواه Google API برای پیاده‌سازی مجوز OAuth 2.0 استفاده می‌کنند. برای اجرای نمونه کدها، ابتدا باید کتابخانه مشتری را برای زبان خود نصب کنید.

وقتی از «کتابخانه کارخواه Google API» برای مدیریت جریان OAuth 2.0 برنامه‌تان استفاده می‌کنید، کتابخانه کارخواه کنش‌های زیادی را انجام می‌دهد که درغیراین‌صورت برنامه باید خودش آن‌ها را مدیریت کند. برای مثال، تعیین می‌کند که برنامه چه زمانی می‌تواند از نشان‌های دسترسی ذخیره‌شده استفاده کند یا آن‌ها را بازآوری کند و همچنین چه زمانی برنامه باید رضایت را دوباره کسب کند. کتابخانه کارخواه همچنین نشانی‌های وب هدایت مجدد صحیح تولید می‌کند و به پیاده‌سازی مدیریت‌کننده‌های هدایت مجدد که کدهای مجوز را با کدهای دسترسی مبادله می‌کنند کمک می‌کند.

«کتابخانه‌های کارخواه Google API» برای برنامه‌های سمت سرور برای زبان‌های زیر دردسترس است:

پیش‌نیازها

فعال کردن میاناهای برنامه‌سازی کاربردی برای پروژه

هر برنامه‌ای که میاناهای برنامه‌سازی کاربردی Google را فراخوانی می‌کند باید آن میاناهای برنامه‌سازی کاربردی را در «کنسول میانای برنامه‌سازی کاربردی» فعال کند.

برای فعال کردن میانای برنامه‌سازی کاربردی برای پروژه:

  1. کتابخانه میانای برنامه‌سازی کاربردی را در «کنسول Google API» باز کنید.
  2. اگر از شما درخواست شد، پروژه‌ای را انتخاب کنید یا پروژه جدیدی بسازید.
  3. «کتابخانه میانای برنامه‌سازی کاربردی» همه میاناهای برنامه‌سازی کاربردی دردسترس را براساس خانواده محصول و محبوبیت گروه‌بندی می‌کند. اگر API موردنظرتان برای فعال کردن در فهرست قابل‌مشاهده نیست، از جستجو برای یافتن آن استفاده کنید، یا روی مشاهده همه در خانواده محصولی که به آن تعلق دارد کلیک کنید.
  4. میانای برنامه‌سازی کاربردی موردنظرتان را برای فعال کردن انتخاب کنید، سپس روی دکمه فعال کردن کلیک کنید.
  5. اگر درخواست شد، صدور صورت‌حساب را فعال کنید.
  6. درصورت درخواست، «شرایط خدمات» API را بخوانید و بپذیرید.

ایجاد اعتبارنامه‌های مجوز

هر برنامه‌ای که از OAuth 2.0 برای دسترسی به Google API استفاده می‌کند باید اعتبارنامه مجوز داشته باشد که برنامه را برای سرور OAuth 2.0 Google شناسایی کند. مراحل زیر نحوه ایجاد اعتبارنامه برای پروژه‌تان را توضیح می‌دهد. سپس برنامه‌هایتان می‌توانند از اطلاعات اعتباری برای دسترسی به میاناهای برنامه‌سازی کاربردی که برای آن پروژه فعال کرده‌اید استفاده کنند.

  1. به صفحه کارخواهان بروید.
  2. روی ایجاد مشتری کلیک کنید.
  3. نوع برنامه برنامه وب را انتخاب کنید.
  4. فرم را تکمیل کنید و روی ایجاد کلیک کنید. برنامه‌هایی که از زبان‌ها و چارچوب‌هایی مثل PHP،‏ Java،‏ Python،‏ Ruby، و NET .استفاده می‌کنند باید URIهای بازهدایت مجاز را مشخص کنند. URIهای هدایت نقاط پایانی هستند که سرور OAuth 2.0 می‌تواند پاسخ‌ها را به آن‌ها ارسال کند. این نقاط پایانی باید از قوانین اعتبارسنجی Google پیروی کنند.

    برای آزمایش، می‌توانید نشانی‌های وب را که به ماشین محلی ارجاع می‌دهند مشخص کنید، برای نمونه http://localhost:8080. همه مثال‌های این سند از http://localhost:8080 به‌عنوان URI هدایت استفاده می‌کنند.

    توصیه می‌کنیم پایانه‌های اصالت‌سنجی برنامه‌تان را به‌گونه‌ای طراحی کنید که برنامه‌تان کدهای مجوز را برای منابع دیگر در صفحه فاش نکند.

پس‌از ایجاد اطلاعات اعتباری، فایل client_secret.json را از «کنسول API» بارگیری کنید. فایل را به‌طور ایمن در مکانی ذخیره کنید که فقط برنامه شما بتواند به آن دسترسی داشته باشد.

شناسایی کردن دامنه‌های دسترسی

محدوده‌ها به برنامه شما امکان می‌دهند فقط به منابعی که نیاز دارد دسترسی پیدا کند و درعین‌حال به کاربران امکان می‌دهند میزان دسترسی‌ای را که به برنامه شما می‌دهند کنترل کنند. بنابراین، ممکن است بین تعداد گستره‌های درخواستی و احتمال دریافت رضایت کاربر رابطه معکوس وجود داشته باشد.

پیش‌از اینکه پیاده‌سازی مجوز OAuth 2.0 را شروع کنید، توصیه می‌کنیم محدوده‌هایی را که برنامه‌تان برای دسترسی به آن‌ها به اجازه نیاز دارد شناسایی کنید.

همچنین توصیه می‌کنیم که برنامه‌تان ازطریق فرایند احراز هویت فزاینده برای دسترسی به دامنه‌های احراز هویت درخواست دهد. در این فرایند، برنامه‌تان برای دسترسی به داده‌های کاربر در بافت درخواست می‌دهد. این رویه مطلوب به کاربران کمک می‌کند راحت‌تر متوجه شوند چرا برنامه شما به دسترسی‌ای که درخواست می‌کند نیاز دارد.

سند OAuth 2.0 API Scopes حاوی فهرست کاملی از دامنه‌هایی است که ممکن است برای دسترسی به Google API استفاده کنید.

الزامات مختص زبان

برای اجرای هرکدام از نمونه کدهای موجود در این سند، به «حساب Google»، دسترسی به اینترنت، و مرورگر وب نیاز دارید. اگر از یکی از کتابخانه‌های کارخواه میانای برنامه‌سازی کاربردی استفاده می‌کنید، الزامات مختص زبان را نیز در بخش‌های زیر ببینید.

PHP

برای اجرای نمونه‌های کد PHP در این سند، به موارد زیر نیاز دارید:

  • PHP نسخه ۸.۰ یا بالاتر با میانای خط فرمان (CLI) و افزونه JSON نصب‌شده.
  • ابزار مدیریت وابستگی Composer.
  • کتابخانه کارخواهان Google APIs برای PHP:

    composer require google/apiclient:^2.15.0

برای اطلاعات بیشتر، کتابخانه مشتری Google APIs برای PHP را ببینید.

Python

برای اجرای نمونه‌های کد Python در این سند، به موارد زیر نیاز دارید:

  • Python نسخه ۳.۷ یا بالاتر
  • ابزار مدیریت بسته pip.
  • نسخه ۲.۰ «کتابخانه کارخواه Google APIs» برای Python:
    pip install --upgrade google-api-python-client
  • google-auth،‏ google-auth-oauthlib، و google-auth-httplib2 برای صدور مجوز کاربر.
    pip install --upgrade google-auth google-auth-oauthlib google-auth-httplib2
  • چارچوب برنامه وب Flask Python.
    pip install --upgrade flask
  • کتابخانه HTTP requests.
    pip install --upgrade requests

اگر نمی‌توانید Python را ارتقا دهید، یادداشت انتشار کتابخانه کارخواه Google API Python و راهنمای انتقال مربوطه را مرور کنید.

Ruby

برای اجرای نمونه‌های کد Ruby در این سند، به موارد زیر نیاز دارید:

  • Ruby نسخه ۲.۶ یا بالاتر
  • کتابخانه Google Auth برای Ruby:

    gem install googleauth
  • کتابخانه‌های کارخواه برای میاناهای برنامه‌سازی کاربردی Google Drive و «تقویم»:

    gem install google-apis-drive_v3 google-apis-calendar_v3
  • چارچوب برنامه وب Sinatra Ruby.

    gem install sinatra

Node.js

برای اجرای نمونه‌های کد Node.js در این سند، به موارد زیر نیاز دارید:

  • نسخه LTS نگهداری، LTS فعال، یا نسخه فعلی Node.js.
  • کارخواه Google APIs Node.js:

    npm install googleapis crypto express express-session

HTTP/REST

برای اینکه بتوانید مستقیماً نقطه‌های پایانی OAuth 2.0 را فراخوانی کنید، نیازی به نصب هیچ کتابخانه‌ای ندارید.

دریافت کدهای دسترسی OAuth 2.0

مراحل زیر نشان می‌دهد که برنامه شما چگونه با سرور OAuth 2.0 Google تعامل می‌کند تا رضایت کاربر را برای انجام درخواست API ازطرف کاربر دریافت کند. برنامه شما باید قبل‌از اجرای درخواست Google API که به مجوز کاربر نیاز دارد، این رضایت را داشته باشد.

فهرست زیر این مراحل را به‌سرعت خلاصه می‌کند:

  1. برنامه شما اجازه‌های موردنیاز خود را مشخص می‌کند.
  2. برنامه شما کاربر را به‌همراه فهرست اجازه‌های درخواست‌شده به Google هدایت می‌کند.
  3. کاربر تصمیم می‌گیرد که اجازه‌ها را به برنامه شما بدهد یا نه.
  4. برنامه شما متوجه می‌شود که کاربر چه تصمیمی گرفته است.
  5. اگر کاربر اجازه‌های درخواست‌شده را اعطا کند، برنامه شما توکن‌های موردنیاز برای ارسال درخواست‌های میانای برنامه‌سازی کاربردی ازطرف کاربر را بازیابی می‌کند.

مرحله ۱: تنظیم پارامترهای مجوز

اولین قدم شما ایجاد درخواست مجوز است. این درخواست پارامترهایی را تنظیم می‌کند که برنامه شما را شناسایی می‌کند و اجازه‌هایی را تعریف می‌کند که از کاربر خواسته می‌شود به برنامه شما اعطا کند.

  • اگر از کتابخانه کارخواه Google برای اصالت‌سنجی و مجوزدهی OAuth 2.0 استفاده می‌کنید، شیئی را ایجاد و پیکربندی می‌کنید که این پارامترها را تعریف می‌کند.
  • اگر مستقیماً نقطه پایانی Google OAuth 2.0 را فراخوانی کنید، نشانی وب تولید خواهید کرد و پارامترها را در آن نشانی وب تنظیم خواهید کرد.

برگه‌های زیر پارامترهای مجوز پشتیبانی‌شده را برای برنامه‌های سرور وب تعریف می‌کنند. نمونه‌های مختص زبان همچنین نشان می‌دهند که چگونه از کتابخانه کارخواه یا کتابخانه مجوز برای پیکربندی شیئی که آن پارامترها را تنظیم می‌کند استفاده کنید:

PHP

تکه‌کد زیر شیء Google\Client() را ایجاد می‌کند که پارامترهای درخواست صدور مجوز را تعریف می‌کند.

آن شیء از اطلاعات فایل client_secret.json شما برای شناسایی برنامه‌تان استفاده می‌کند. (برای اطلاعات بیشتر درباره آن فایل، ایجاد اعتبارنامه‌های مجوز را ببینید.) این شیء همچنین دامنه‌هایی را که برنامه‌تان برای دسترسی به آن‌ها درخواست اجازه می‌کند و نشانی وب نقطه پایانی اصالت‌سنجی برنامه‌تان را که پاسخ سرور OAuth 2.0 در Google را مدیریت می‌کند شناسایی می‌کند. در نهایت، کد پارامترهای اختیاری access_type و include_granted_scopes را تنظیم می‌کند.

برای مثال، این کد دسترسی آفلاین فقط خواندنی به فراداده «Google Drive» و رویدادهای «تقویم» کاربر را درخواست می‌کند:

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

تکه کد زیر از واحد google-auth-oauthlib.flow برای ساختن درخواست مجوز استفاده می‌کند.

کد یک شیء Flow می‌سازد که برنامه شما را بااستفاده از اطلاعات فایل client_secret.json که پس‌از ایجاد اطلاعات کاربری مجوز بارگیری کرده‌اید شناسایی می‌کند. این شیء همچنین دامنه‌هایی را که برنامه شما برای دسترسی به آن‌ها درخواست اجازه می‌کند و نشانی وب نقطه پایانی اصالت‌سنجی برنامه شما را که پاسخ سرور OAuth 2.0 در Google را مدیریت می‌کند، شناسایی می‌کند. درنهایت، کد پارامترهای اختیاری access_type و include_granted_scopes را تنظیم می‌کند.

برای مثال، این کد دسترسی آفلاین فقط خواندنی به فراداده «Google Drive» و رویدادهای «تقویم» کاربر را درخواست می‌کند:

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

از فایل client_secrets.json که ایجاد کرده‌اید برای پیکربندی شیء کارخواه در برنامه‌تان استفاده کنید. وقتی شیء کارخواه را پیکربندی می‌کنید، دامنه‌هایی را که برنامه‌تان برای دسترسی به آن‌ها نیاز دارد مشخص می‌کنید، و همچنین نشانی وب نقطه پایان اصالت‌سنجی برنامه‌تان را که پاسخ سرور OAuth 2.0 را مدیریت می‌کند مشخص می‌کنید.

برای مثال، این کد درخواست دسترسی آفلاین فقط خواندنی به فراداده Google Drive و رویدادهای «تقویم» کاربر را می‌دهد:

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)

برنامه شما از شیء کارخواه برای انجام عملیات OAuth 2.0 استفاده می‌کند، مانند تولید نشانی‌های وب درخواست مجوز و اعمال کد دسترسی به درخواست‌های HTTP.

Node.js

تکه‌کد زیر شیء google.auth.OAuth2 را ایجاد می‌کند که پارامترهای درخواست صدور مجوز را تعریف می‌کند.

آن شیء از اطلاعات فایل client_secret.json برای شناسایی برنامه شما استفاده می‌کند. برای درخواست اجازه از کاربر برای بازیابی کد دسترسی، او را به صفحه موافقت هدایت می‌کنید. برای ایجاد نشانی وب صفحه موافقت:

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

نکته مهم - refresh_token فقط در اولین مجوز برگردانده می‌شود. جزئیات بیشتر اینجا.

HTTP/REST

نقطه پایانی Google OAuth 2.0 در https://accounts.google.com/o/oauth2/v2/auth است. این نقطه پایانی فقط ازطریق HTTPS قابل‌دسترسی است. اتصال‌های HTTP ساده رد می‌شود.

سرور مجوز Google از پارامترهای رشته پُرسمان زیر برای برنامه‌های سرور وب پشتیبانی می‌کند:

پارامترها
client_id الزامی

شناسه کارخواه برای برنامه شما. این مقدار را می‌توانید در «کنسول Cloud» صفحه «کارخواه‌ها» پیدا کنید.

redirect_uri الزامی

تعیین می‌کند که سرور API کاربر را پس‌از تکمیل جریان مجوز به کجا هدایت کند. این مقدار باید دقیقاً با یکی از URIهای هدایت مجاز برای کارخواه OAuth 2.0 که در صفحه «کارخواه‌ها» در Cloud Console کارخواه پیکربندی کرده‌اید مطابقت داشته باشد. اگر این مقدار با شناسه منبع یکسان هدایت مجاز برای client_id ارائه‌شده مطابقت نداشته باشد، خطای redirect_uri_mismatch دریافت خواهید کرد.

توجه داشته باشید که طرح http یا https، حروف بزرگ و کوچک، و خط مورب پایانی ('/') باید همگی مطابقت داشته باشند.

response_type الزامی

تعیین می‌کند که آیا نقطه پایان Google OAuth 2.0 کد مجوز برمی‌گرداند یا نه.

برای برنامه‌های کارساز وب، مقدار پارامتر را روی code تنظیم کنید.

scope الزامی

فهرستی از حوزه‌ها که با فاصله از هم جدا شده‌اند و منابعی را که برنامه شما می‌تواند ازطرف کاربر به آن‌ها دسترسی داشته باشد شناسایی می‌کند. این مقادیر به صفحه رضایت که Google به کاربر نمایش می‌دهد اطلاع‌رسانی می‌کند.

گستره‌ها به برنامه شما امکان می‌دهند فقط به منابعی که نیاز دارد دسترسی داشته باشد و درعین‌حال به کاربران امکان می‌دهند میزان دسترسی‌ای را که به برنامه شما می‌دهند کنترل کنند. بنابراین، بین تعداد محدوده‌های درخواستی و احتمال دریافت رضایت کاربر رابطه معکوس وجود دارد.

توصیه می‌کنیم برنامه‌تان درصورت امکان، دسترسی به گستره‌های مجوز را در بافت درخواست کند. با درخواست دسترسی به داده‌های کاربر در بافت، بااستفاده از مجوز فزاینده، به کاربران کمک می‌کنید متوجه شوند چرا برنامه شما به دسترسی‌ای که درخواست می‌کند نیاز دارد.

access_type توصیه‌شده

نشان می‌دهد که آیا برنامه شما می‌تواند کد دسترسی را وقتی کاربر در مرورگر حضور ندارد بازآوری کند یا نه. مقادیر معتبر پارامتر online است که مقدار پیش‌فرض است و offline.

اگر برنامه شما نیاز دارد کد دسترسی را وقتی کاربر در مرورگر حضور ندارد بازآوری کند، مقدار را روی offline تنظیم کنید. این روش بازآوری کدهای دسترسی است که در ادامه این سند شرح داده شده است. این مقدار به سرور مجوز Google دستور می‌دهد اولین باری که برنامه شما کد مجوز را با ژتون‌ها معاوضه می‌کند، ژتون بازآوری و کد دسترسی را برگرداند.

state توصیه‌شده

هر مقدار رشته‌ای را که برنامه شما برای حفظ وضعیت بین درخواست مجوز شما و پاسخ سرور مجوز استفاده می‌کند، مشخص می‌کند. سرور مقدار دقیقی را که به‌عنوان جفت name=value در مؤلفه پُرسمان نشانی وب (?) از redirect_uri ارسال می‌کنید، پس‌از اینکه کاربر با درخواست دسترسی برنامه‌تان موافقت یا مخالفت کرد، برمی‌گرداند.

می‌توانید از این پارامتر برای اهداف مختلفی استفاده کنید، ازجمله هدایت کاربر به منبع صحیح در برنامه‌تان، ارسال نانس، و کاهش جعل درخواست بین‌سایتی. ازآنجایی‌که redirect_uri شما قابل حدس زدن است، استفاده از مقدار state می‌تواند اطمینان شما را از اینکه اتصال ورودی نتیجه درخواست اصالت‌سنجی است افزایش دهد. اگر رشته‌ای تصادفی تولید کنید یا درهم‌سازی کوکی یا مقدار دیگری را که وضعیت کارخواه را ثبت می‌کند کدگذاری کنید، می‌توانید پاسخ را اعتبارسنجی کنید تا علاوه‌براین مطمئن شوید که درخواست و پاسخ از یک مرورگر منشأ گرفته‌اند و دربرابر حملاتی مثل جعل درخواست بین‌سایتی محافظت کنید. برای نمونه‌ای از نحوه ایجاد و تأیید کردن نشان state، به مستندات OpenID Connect مراجعه کنید.

include_granted_scopes اختیاری

برنامه‌ها را قادر می‌سازد تا از مجوز افزایشی برای درخواست دسترسی به دامنه‌های اضافی در بافت استفاده کنند. اگر مقدار این پارامتر را روی true تنظیم کنید و درخواست صدور مجوز اعطا شود، رمز دسترسی جدید همچنین شامل هر محدوده‌ای می‌شود که کاربر قبلاً به برنامه اجازه دسترسی به آن را داده است. برای مشاهده نمونه‌ها، بخش مجوز افزایشی را ببینید.

login_hint اختیاری

اگر برنامه شما می‌داند کدام کاربر درحال تلاش برای اصالت‌سنجی است، می‌تواند از این پارامتر برای ارائه راهنمایی به «سرور اصالت‌سنجی Google» استفاده کند. سرور از این راهنمایی برای ساده کردن جریان ورود به سیستم استفاده می‌کند، یا با پیش‌تکمیل کردن فیلد ایمیل در فرم ورود به سیستم یا با انتخاب جلسه چندورودی مناسب.

مقدار پارامتر را روی نشانی ایمیل یا شناسه sub تنظیم کنید که معادل شناسه Google کاربر است.

prompt اختیاری

فهرست پیام‌واره‌های حساس به حروف بزرگ و کوچک که با فاصله از هم جدا شده‌اند و به کاربر ارائه می‌شود. اگر این پارامتر را مشخص نکنید، فقط اولین باری که پروژه شما درخواست دسترسی می‌کند، از کاربر درخواست خواهد شد. برای اطلاعات بیشتر، درخواست مجدد برای موافقت را ببینید.

مقادیر ممکن عبارت‌اند از:

none هیچ صفحه تأیید هویت یا رضایتی نمایش داده نمی‌شود. نباید با مقادیر دیگر مشخص شود.
consent از کاربر درخواست رضایت کنید.
select_account از کاربر بخواهید حسابی را انتخاب کند.

مرحله ۲: هدایت کردن به سرور OAuth 2.0 در Google

کاربر را به سرور OAuth 2.0 Google هدایت کنید تا فرایند اصالت‌سنجی و صدور مجوز را آغاز کند. معمولاً این اتفاق زمانی می‌افتد که برنامه شما برای اولین‌بار نیاز به دسترسی به داده‌های کاربر دارد. درصورت مجوزدهی افزایشی، این مرحله زمانی نیز رخ می‌دهد که برنامه شما برای اولین‌بار نیاز به دسترسی به منابع اضافی دارد که اجازه دسترسی به آن‌ها را ندارد.

PHP

  1. نشانی وبی برای درخواست دسترسی از سرور OAuth 2.0 متعلق به Google ایجاد کنید:
    $auth_url = $client->createAuthUrl();
  2. کاربر را به $auth_url هدایت کنید:
    header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));

Python

این مثال نشان می‌دهد که چگونه می‌توان کاربر را بااستفاده از چارچوب برنامه وب Flask به نشانی وب اصالت‌سنجی هدایت کرد:

return flask.redirect(authorization_url)

Ruby

  1. نشانی وبی برای درخواست دسترسی از سرور OAuth 2.0 Google تولید کنید:
    auth_uri = authorizer.get_authorization_url(request: request)
  2. کاربر را به auth_uri هدایت کنید.

Node.js

  1. از نشانی وب تولیدشده authorizationUrl از روش مرحله ۱ generateAuthUrl برای درخواست دسترسی از سرور Google OAuth 2.0 استفاده کنید.
  2. کاربر را به authorizationUrl هدایت کنید.
    res.redirect(authorizationUrl);

HTTP/REST

نمونه هدایت به سرور مجوز Google

نشانی وب نمونه در زیر نشان داده شده است، با شکست خط و فاصله برای خوانایی.

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 متعلق به Google کاربر را اصالت‌سنجی می‌کند و موافقت کاربر را برای دسترسی برنامه شما به دامنه‌های درخواستی دریافت می‌کند. پاسخ بااستفاده از نشانی وب هدایت مجددی که مشخص کرده‌اید به برنامه‌تان ارسال می‌شود.

مرحله ۳: Google از کاربر درخواست رضایت می‌کند

در این مرحله، کاربر تصمیم می‌گیرد که دسترسی درخواستی را به برنامه شما اعطا کند یا نه. در این مرحله، Google پنجره رضایتی را نمایش می‌دهد که نام برنامه شما و سرویس‌های Google API را که برنامه برای دسترسی به آن‌ها با اطلاعات اعتباری مجوز کاربر درخواست اجازه می‌کند و خلاصه‌ای از دامنه‌های دسترسی که باید اعطا شود نشان می‌دهد. سپس کاربر می‌تواند با اعطای دسترسی به یک یا چند حوزه درخواست‌شده توسط برنامه شما موافقت کند یا درخواست را رد کند.

برنامه شما در این مرحله نیازی به انجام کاری ندارد زیرا منتظر پاسخ سرور OAuth 2.0 از Google است که نشان می‌دهد آیا دسترسی اعطا شده است یا خیر. آن پاسخ در مرحله بعدی توضیح داده شده است.

خطاها

درخواست‌های ارسال‌شده به نقطه پایانی مجوز OAuth 2.0 در Google ممکن است به‌جای جریان‌های اصالت‌سنجی و مجوز موردانتظار، پیام‌های خطای سَمت کاربر را نمایش دهند. کدهای خطای رایج و راه‌حل‌های پیشنهادی عبارت‌اند از:

admin_policy_enforced

«حساب Google» به‌دلیل خط‌مشی‌های سرپرست Google Workspace خود نمی‌تواند یک یا چند دامنه درخواستی را مجاز کند. برای کسب اطلاعات بیشتر درباره اینکه سرپرست چگونه می‌تواند دسترسی به همه دامنه‌ها یا دامنه‌های حساس و محدودشده را تا زمانی که دسترسی صریحاً به شناسه کارخواه OAuth شما اعطا شود محدود کند، به مقاله راهنمای سرپرست Google Workspace کنترل اینکه کدام برنامه‌های داخلی و طرف سوم به داده‌های Google Workspace دسترسی داشته باشند مراجعه کنید.

disallowed_useragent

نقطه پایان مجوز در یک عامل کاربر جاسازی‌شده نمایش داده می‌شود که توسط خط‌مشی‌های OAuth 2.0 Google مجاز نیست.

توسعه‌دهندگان iOS و macOS ممکن است هنگام باز کردن درخواست‌های مجوز در WKWebView با این خطا مواجه شوند. توسعه‌دهندگان باید درعوض از کتابخانه‌های iOS مثل ورود به سیستم با Google برای iOS یا AppAuth برای iOS از OpenID Foundation استفاده کنند.

توسعه‌دهندگان وب ممکن است زمانی با این خطا مواجه شوند که برنامه iOS یا macOS پیوند وب عمومی را در عامل کاربر جاسازی‌شده باز کند و کاربر از سایت شما به نقطه پایانی مجوز OAuth 2.0 در Google پیمایش کند. توسعه‌دهندگان باید اجازه دهند پیوندهای عمومی در مدیریت‌کننده پیوند پیش‌فرض سیستم‌عامل باز شوند، که شامل هر دو مدیریت‌کننده پیوندهای جهانی یا برنامه مرورگر پیش‌فرض می‌شود. کتابخانه SFSafariViewController نیز گزینه پشتیبانی‌شده‌ای است.

org_internal

شناسه کارخواه OAuth در درخواست بخشی از پروژه‌ای است که دسترسی به «حساب‌های Google» را در سازمان Google Cloud خاصی محدود می‌کند. برای اطلاعات بیشتر درباره این گزینه پیکربندی، به بخش نوع کاربر در مقاله راهنمای «راه‌اندازی صفحه رضایت OAuth» مراجعه کنید.

invalid_client

رمز کارخواه OAuth نادرست است. پیکربندی کارخواه OAuth، ازجمله شناسه کارخواه و رمز استفاده‌شده برای این درخواست را مرور کنید.

deleted_client

کارخواه OAuth که برای درخواست استفاده می‌شود حذف شده است. حذف می‌تواند به‌صورت دستی یا به‌طور خودکار درصورت استفاده نشدن از کارخواه‌ها انجام شود. مشتریان حذف‌شده را می‌توان ظرف ۳۰ روز پس‌از حذف بازیابی کرد. بیشتر بدانید .

invalid_grant

هنگام بازآوری کد دسترسی یا استفاده از مجوز افزایشی، ممکن است کد منقضی شده باشد یا نامعتبر شده باشد. کاربر را دوباره اصالت‌سنجی کنید و برای دریافت نشان‌های جدید، از کاربر بخواهید رضایت دهد. اگر همچنان این خطا را می‌بینید، مطمئن شوید که برنامه‌تان به‌درستی پیکربندی شده است و از نشان‌ها و پارامترهای صحیح در درخواستتان استفاده می‌کنید. درغیراین‌صورت، ممکن است حساب کاربر حذف یا غیرفعال شده باشد.

redirect_uri_mismatch

redirect_uri ارسال‌شده در درخواست مجوز با نشانی وب هدایت مجاز برای شناسه کارخواه OAuth مطابقت ندارد. URIهای هدایت مجاز را در Google Cloud Console صفحه کارخواه‌ها مرور کنید.

پارامتر redirect_uri ممکن است به جریان OAuth خارج‌از باند (OOB) اشاره داشته باشد که منسوخ شده است و دیگر پشتیبانی نمی‌شود. برای به‌روزرسانی یکپارچه‌سازی خود، به راهنمای انتقال مراجعه کنید.

invalid_request

مشکلی در درخواست شما وجود داشت. این مشکل ممکن است به چند دلیل باشد:

  • درخواست به‌درستی قالب‌بندی نشده است
  • پارامترهای الزامی در درخواست وجود نداشت
  • درخواست از روش صدور مجوزی استفاده می‌کند که Google از آن پشتیبانی نمی‌کند. تأیید کنید که ادغام OAuth شما از روش ادغام توصیه‌شده استفاده می‌کند

مرحله ۴: رسیدگی به پاسخ سرور OAuth 2.0

سرور OAuth 2.0 بااستفاده از نشانی وب مشخص‌شده در درخواست، به درخواست دسترسی برنامه‌تان پاسخ می‌دهد.

اگر کاربر درخواست دسترسی را تأیید کند، پاسخ حاوی کد مجوز خواهد بود. اگر کاربر درخواست را تأیید نکند، پاسخ حاوی پیام خطا است. کد مجوز یا پیام خطایی که به سرور وب برگردانده می‌شود در رشته پُرسمان نمایش داده می‌شود، همان‌طور که در مثال‌های زیر نشان داده شده است:

پاسخ خطا:

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

پاسخ کد مجوز:

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

پاسخ سرور نمونه OAuth 2.0

با کلیک کردن روی نشانی وب نمونه زیر می‌توانید این جریان را آزمایش کنید. این نشانی وب دسترسی فقط خواندنی برای مشاهده فراداده‌های فایل‌های Google Drive شما و دسترسی فقط خواندنی برای مشاهده رویدادهای «تقویم Google» شما درخواست می‌کند:

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، مرورگرتان شما را به OAuth 2.0 Playground، ابزاری برای آزمایش جریان‌های OAuth، هدایت می‌کند. خواهید دید که OAuth 2.0 Playground به‌طور خودکار کد مجوز را ضبط کرده است.

مرحله ۵: معاوضه کد مجوز با ژتون‌های بازآوری و دسترسی

پس‌از اینکه سرور وب کد مجوز را دریافت کرد، می‌تواند کد مجوز را با کد دسترسی معاوضه کند.

PHP

برای تبدیل کد مجوز به کد دسترسی، از روش fetchAccessTokenWithAuthCode استفاده کنید:

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

Python

در صفحه بازگشت تماس، از کتابخانه google-auth برای تأیید پاسخ سرور مجوزدهی استفاده کنید. سپس، از روش flow.fetch_token برای مبادله کد مجوز در آن پاسخ با کد دسترسی استفاده کنید:

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

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

# Store the credentials in 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

در صفحه callback، از کتابخانه googleauth برای تأیید پاسخ سرور مجوزدهی استفاده کنید. از روش authorizer.handle_auth_callback_deferred برای ذخیره کردن کد مجوز و هدایت مجدد به نشانی وبی که در ابتدا درخواست مجوز کرده بود استفاده کنید. این کار تبادل کد را با ذخیره موقت نتایج در جلسه کاربر به‌تعویق می‌اندازد.

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

Node.js

برای تبدیل کد مجوز به کد دسترسی، از روش getToken استفاده کنید:

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

برای تبدیل کد مجوز به کد دسترسی، با نقطه پایانی https://oauth2.googleapis.com/token تماس بگیرید و پارامترهای زیر را تنظیم کنید:

فیلدها
client_id شناسه کارخواه به‌دست‌آمده از صفحه کارخواه‌ها در «کنسول Cloud».
client_secret اختیاری

رمز کارخواه دریافت‌شده از «کنسول Cloud» صفحه کارخواه‌ها.

code کد مجوز برگشت‌داده‌شده از درخواست اولیه.
grant_type همان‌طور که در مشخصات OAuth 2.0 تعریف شده است، مقدار این فیلد باید روی authorization_code تنظیم شود.
redirect_uri یکی از URIهای هدایت فهرست‌شده برای پروژه‌تان در صفحه کارخواه‌ها در Cloud Console برای client_id داده‌شده.

هرچند استفاده از DPoP اختیاری است، اما برای افزایش امنیت توصیه می‌شود. امنیت DPoP به محدود بودن کلید خصوصی به یک دستگاه بستگی دارد؛ توصیه می‌کنیم آن را به‌گونه‌ای ذخیره کنید که نتوان آن را از دستگاه کپی کرد، مثلاً بااستفاده از TPM،‏ Secure Enclave، یا دیگر محل‌های ذخیره کلید با پشتیبانی سخت‌افزاری. برای استفاده از DPoP، برنامه شما باید برای هر درخواست به نقطه پایانی رمز، یک JWT اثبات DPoP جدید و منحصربه‌فرد تولید کند و آن را به‌عنوان سرصفحه درخواست HTTP اضافه کند.

سرایند الزامی شرح
DPoP اختیاری اثبات DPoP یک JWT است که مالکیت کلید خصوصی را اثبات می‌کند. این سرصفحه است، نه پارامتر. درصورت ارائه، نشان‌های برگردانده‌شده به این کلید محدود می‌شوند. برای هر درخواست باید مدرک جدید و منحصربه‌فردی تولید شود و باید شامل ادعاهای htm (روش HTTP) و htu (نشانی وب HTTP) باشد که با درخواست مطابقت داشته باشد.

قطعه کد زیر یک درخواست نمونه را نشان می‌دهد:

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

مراحل زیر نحوه ساختن اثبات DPoP بااستفاده از OpenSSL از خط فرمان را نشان می‌دهد:

  1. تولید جفت کلید EC P-256:
    openssl ecparam -name prime256v1 -genkey -noout -out dpop_private.pem
    openssl ec -in dpop_private.pem -pubout -out dpop_public.pem
  2. ایجاد سرایند DPoP:

    سرصفحه باید شامل ادعاهای typ، alg، و jwk (کلید عمومی) باشد. مقادیر x و y مختصات کدبندی‌شده با Base64Url کلید عمومی EC شما است. این JSON را با Base64Url کدبندی کنید:

    {
      "typ":"dpop+jwt",
      "alg":"ES256",
      "jwk": {
        "kty":"EC",
        "x":"YOUR_PUBLIC_KEY_X",
        "y":"YOUR_PUBLIC_KEY_Y",
        "crv":"P-256"
      }
    }
  3. ایجاد بار داده DPoP:

    بار داده باید شامل jti (شناسه یکتا برای درخواست)، htm (روش HTTP، مثلاً POST)، htu (HTTP URI، مثلاً https://oauth2.googleapis.com/token)، و iat (زمان صدور) باشد. اگر در پاسخ به درخواست قبلی، یک nonce از سرور در سربرگ DPoP-Nonce دریافت کردید، باید آن مقدار nonce را در ادعای nonce قرار دهید. ادعای nonce برای تبادل کد مجوز اختیاری است و فقط زمانی استفاده می‌شود که سرایند DPoP-Nonce قبلاً دریافت شده باشد. این JSON را با Base64Url کدبندی کنید:

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

    مقدار jti به نوع مبادله بستگی دارد:

    • برای تبادل کد مجوز، jti باید درهم‌سازی SHA256 کد مجوز باشد که با Base64Url کدبندی شده است: "jti":"BASE64URL(SHA256(AUTHORIZATION_CODE))".
    • برای تبادل‌های کد نوسازی، jti باید یک شناسه یکتای هر درخواست باشد: "jti":"YOUR_UNIQUE_PER_REQUEST_IDENTIFIER".
  4. امضای مدرک:

    سرصفحه و بار داده کدگذاری‌شده را با نقطه (.) به‌هم متصل کنید، سپس نتیجه را با کلید خصوصی‌تان بااستفاده از ES256 امضا کنید. توجه داشته باشید که JWS الزام می‌کند که امضا در قالب خام R | S به‌هم‌پیوسته باشد (۶۴ بایت برای P-256). اگر مستقیماً از OpenSSL استفاده می‌کنید، باید امضای پیش‌فرض ASN.1 DER-encoded را به این قالب خام تبدیل کنید.

تبادل موفق با پاسخ 200 OK حاوی نشان‌ها مشخص می‌شود. اگر درطول تبادل از اثبات DPoP معتبری استفاده شود، کد بازآوری که Google برمی‌گرداند به کلید شما محدود به DPoP خواهد بود، اما کدهای دسترسی محدود به DPoP نخواهند بود. کدهای دسترسی به‌جای DPoP، token_type مربوط به Bearer را حفظ خواهند کرد. علاوه‌براین، Google سرصفحه HTTP DPoP-Nonce را در پاسخ برمی‌گرداند. کارخواه شما باید این عدد یک‌بارمصرف را ذخیره کند و آن را در ادعای nonce اثبات DPoP در درخواست‌های بعدی (مانند هنگام تبادل یک کد بازآوری برای یک کد دسترسی جدید، یا هنگام فراخوانی میاناهای برنامه‌سازی کاربردی محافظت‌شده با DPoP) قرار دهد. بااستفاده از این عدد یک‌بارمصرف صادرشده زودهنگام، می‌توانید از خطای رفت‌وبرگشت اضافی (use_dpop_nonce) در درخواست بعدی‌تان جلوگیری کنید.

برای درخواست‌های تبادل ژتون که با ژتون‌های بازآوری محدودشده با DPoP انجام می‌شود، باید اثبات‌های DPoP اضافه شود.

اگر سرایند DPoP در زمان موردانتظار وجود نداشته باشد، نامعتبر باشد، یا اگر مدرک از کلیدی متفاوت با کلید محدودشده به کد استفاده کند، تبادل ناموفق رخ می‌دهد. در این موارد، سرور خطای 400 Bad Request را برمی‌گرداند. اگر اثبات DPoP دارای ادعاهای htm یا htu نامطابق، iat منقضی‌شده، jti دوباره استفاده‌شده، یا امضای نامعتبر باشد، Google کد خطای invalid_dpop_proof را برمی‌گرداند. اگر یک DPoP nonce لازم باشد، مثلاً درطول تبادل ژتون بازآوری، و اثبات DPoP فاقد ادعای nonce باشد، یا مقدار nonce برای سرور غیرقابل‌قبول باشد (مثلاً منقضی شده باشد، قبلاً استفاده شده باشد، یا نادرست باشد)، Google کد خطای use_dpop_nonce را به‌همراه سرصفحه HTTP‏ DPoP-Nonce حاوی یک nonce جدید برمی‌گرداند که می‌توانید در درخواست بعدی استفاده کنید. خطاهای دیگر ممکن است invalid_grant را برگرداند.

Google با برگرداندن شیء JSON که حاوی کد دسترسی کوتاه‌مدت و کد بازآوری است به این درخواست پاسخ می‌دهد. توجه داشته باشید که ژتون بازآوری فقط درصورتی برگردانده می‌شود که برنامه شما پارامتر access_type را در درخواست اولیه به سرور مجوز Google روی offline تنظیم کرده باشد.

پاسخ شامل فیلدهای زیر است:

فیلدها
access_token نشانه‌ای که برنامه شما برای صدور مجوز درخواست Google API ارسال می‌کند.
expires_in مدت‌زمان باقی‌مانده کد دسترسی برحسب ثانیه.
refresh_token کدی که می‌توانید از آن برای دریافت کد دسترسی جدید استفاده کنید. کدهای بازآوری تا زمانی که کاربر دسترسی را لغو کند یا کد بازآوری منقضی شود معتبر هستند. اگر از DPoP استفاده شده باشد، ژتون بازآوری به کلید خصوصی استفاده‌شده برای امضای اثبات DPoP محدود می‌شود. مجدداً، این فیلد فقط درصورتی در این پاسخ وجود دارد که پارامتر access_type را در درخواست اولیه به سرور مجوز Google روی offline تنظیم کرده باشید.
refresh_token_expires_in طول عمر باقی‌مانده ژتون بازآوری به ثانیه. این مقدار فقط زمانی تنظیم می‌شود که کاربر دسترسی زمان‌دار اعطا کند.
scope دامنه‌های دسترسی اعطاشده توسط access_token به‌صورت فهرستی از رشته‌های حساس به حروف بزرگ و کوچک که با فاصله از هم جدا شده‌اند بیان می‌شود.
token_type نوع کد برگردانده‌شده. این مقدار همیشه Bearer است، حتی وقتی از DPoP استفاده می‌شود.

تکه‌کد زیر نمونه‌ای از سرایندها و متن پاسخ موفقیت‌آمیز را هنگام استفاده از DPoP نشان می‌دهد:

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

خطاها

هنگام معاوضه کد مجوز با کد دسترسی، ممکن است به‌جای پاسخ موردانتظار با خطای زیر مواجه شوید. کدهای خطای رایج و راه‌حل‌های پیشنهادی در این بخش فهرست شده‌اند.

invalid_grant

کد تأییدیه ارائه‌شده نامعتبر است یا قالب آن نادرست است. با بازراه‌اندازی فرایند OAuth، کد جدیدی درخواست کنید تا دوباره از کاربر درخواست رضایت شود.

مرحله ۶: بررسی کردن گستره‌هایی که کاربران اعطا کرده‌اند

هنگام درخواست چندین اجازه (محدوده)، ممکن است کاربران به برنامه شما اجازه دسترسی به همه آن‌ها را ندهند. برنامه شما باید تأیید کند که کدام دامنه‌ها واقعاً اعطا شده‌اند و موقعیت‌هایی را که برخی‌از اجازه‌ها رد شده‌اند به‌درستی مدیریت کند، معمولاً با غیرفعال کردن ویژگی‌هایی که به آن دامنه‌های ردشده متکی هستند.

بااین‌حال، چند استثنا وجود دارد. برنامه‌های Google Workspace Enterprise با واگذاری اختیارات در سراسر دامنه، یا برنامه‌هایی که به‌عنوان مورد اعتماد علامت‌گذاری شده‌اند، صفحه رضایت اجازه‌های ریزدانه را دور می‌زنند. برای این برنامه‌ها، کاربران صفحه رضایت اجازه دانه‌ای را نخواهند دید. درعوض، برنامه‌تان یا همه گستره‌های درخواست‌شده را دریافت می‌کند یا هیچ‌کدام را دریافت نمی‌کند.

برای اطلاعات دقیق‌تر، نحوه مدیریت اجازه‌های ریزدانه را ببینید.

PHP

برای بررسی اینکه کاربر کدام دامنه‌ها را اعطا کرده است، از روش getGrantedScope() استفاده کنید:

// 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

شیء credentials برگردانده‌شده دارای ویژگی granted_scopes است، که فهرستی از دامنه‌هایی است که کاربر به برنامه شما اعطا کرده است.

credentials = flow.credentials
flask.session['credentials'] = {
    '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

Ruby

هنگام درخواست چند گستره به‌طور هم‌زمان، بررسی کنید کدام گستره‌ها ازطریق ویژگی scope شیء credentials اعطا شده‌اند.

# 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

هنگام درخواست چند گستره به‌طور هم‌زمان، بررسی کنید کدام گستره‌ها ازطریق ویژگی scope شیء 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.
  // 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

برای بررسی اینکه آیا کاربر به برنامه شما اجازه دسترسی به یک حوزه خاص را داده است یا نه، فیلد scope را در پاسخ کد دسترسی بررسی کنید. حوزه‌های دسترسی اعطاشده توسط access_token که به‌صورت فهرستی از رشته‌های حساس به حروف بزرگ و کوچک با فاصله از هم بیان شده است.

برای مثال، پاسخ کد دسترسی نمونه زیر نشان می‌دهد که کاربر به برنامه شما اجازه دسترسی به اجازه‌های فعالیت Drive فقط خواندنی و رویدادهای «تقویم» را داده است:

  {
    "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

PHP

با تکمیل مراحل زیر، از کد دسترسی برای فراخوانی Google APIs استفاده کنید:

  1. اگر نیاز دارید یک کد دسترسی را به یک شیء جدید Google\Client اعمال کنید — برای مثال، اگر کد دسترسی را در یک جلسه کاربر ذخیره کرده‌اید — از روش setAccessToken استفاده کنید:
    $client->setAccessToken($access_token);
  2. برای API که می‌خواهید فراخوانی کنید، یک شیء سرویس بسازید. با ارائه شیء Google\Client مجاز به سازنده برای API که می‌خواهید فراخوانی کنید، شیء سرویس می‌سازید. برای مثال، برای فراخوانی Drive API:
    $drive = new Google\Service\Drive($client);
  3. بااستفاده از میانای ارائه‌شده توسط شیء سرویس، درخواست‌هایی به سرویس میانای برنامه‌سازی کاربردی ارسال کنید. برای مثال، برای فهرست کردن فایل‌ها در Google Drive کاربر اصالت‌سنجی‌شده:
    $files = $drive->files->listFiles(array());

Python

پس‌از دریافت کد دسترسی، برنامه‌تان می‌تواند از آن کد برای صدور مجوز درخواست‌های API ازطرف حساب کاربری یا حساب سرویس مشخصی استفاده کند. از اطلاعات اعتباری مجوز ویژه کاربر برای ساختن یک شیء سرویس برای API که می‌خواهید فراخوانی کنید استفاده کنید، و سپس از آن شیء برای ایجاد درخواست‌های API مجاز استفاده کنید.

  1. یک شیء سرویس برای API که می‌خواهید فراخوانی کنید بسازید. با فراخوانی روش build کتابخانه googleapiclient.discovery با نام و نسخه API و اطلاعات کاربری کاربر، یک شیء سرویس می‌سازید: برای مثال، برای فراخوانی نسخه ۳ Drive API:
    from googleapiclient.discovery import build
    
    drive = build('drive', 'v2', credentials=credentials)
  2. بااستفاده از میانای ارائه‌شده توسط شیء سرویس، درخواست‌ها را به سرویس میانای برنامه‌سازی کاربردی ارسال کنید. برای مثال، برای فهرست کردن فایل‌ها در Google Drive کاربر اصالت‌سنجی‌شده:
    files = drive.files().list().execute()

Ruby

پس‌از دریافت کد دسترسی، برنامه شما می‌تواند از آن کد برای درخواست‌های API ازطرف حساب کاربری یا حساب سرویس معین استفاده کند. از اطلاعات اعتباری مجوز مختص کاربر برای ساختن شیء سرویس برای API که می‌خواهید فراخوانی کنید استفاده کنید، و سپس از آن شیء برای ایجاد درخواست‌های API مجاز استفاده کنید.

  1. یک شیء سرویس برای API که می‌خواهید فراخوانی کنید بسازید. برای مثال، برای فراخوانی نسخه ۳ از Drive API:
    drive = Google::Apis::DriveV3::DriveService.new
  2. اطلاعات کاربری را در سرویس تنظیم کنید:
    drive.authorization = credentials
  3. بااستفاده از میانای ارائه‌شده توسط شیء سرویس، درخواست‌هایی به سرویس میانای برنامه‌سازی کاربردی ارسال کنید. برای مثال، برای فهرست کردن فایل‌ها در Google Drive کاربر اصالت‌سنجی‌شده:
    files = drive.list_files

یا اینکه با ارائه پارامتر options به یک روش، مجوز را می‌توان براساس هر روش ارائه کرد:

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

Node.js

پس‌از دریافت کد دسترسی و تنظیم آن روی شیء OAuth2، از شیء برای فراخوانی Google APIs استفاده کنید. برنامه شما می‌تواند از این کد برای مجاز کردن درخواست‌های API ازطرف حساب کاربری یا حساب سرویس معین استفاده کند. برای API که می‌خواهید فراخوانی کنید، یک شیء سرویس بسازید. برای مثال، کد زیر از Google Drive API برای فهرست کردن نام فایل‌ها در Drive کاربر استفاده می‌کند.

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

پس‌از اینکه برنامه‌تان کد دسترسی را دریافت کرد، می‌توانید از این کد برای برقراری تماس با Google API ازطرف حساب کاربری مشخصی استفاده کنید، به‌شرطی که گستره(های) دسترسی موردنیاز API اعطا شده باشد. برای انجام این کار، کد دسترسی را در درخواست به میانای برنامه‌سازی کاربردی با افزودن پارامتر access_token پُرسمان یا مقدار Authorization سرصفحه HTTP Bearer اضافه کنید. درصورت امکان، سرصفحه HTTP ترجیح داده می‌شود، زیرا رشته‌های پُرسمان معمولاً در گزارش‌های سرور قابل‌مشاهده هستند. در بیشتر موارد می‌توانید از کتابخانه کارخواه برای راه‌اندازی فراخوانی‌هایتان به Google APIs استفاده کنید (برای مثال، هنگام فراخوانی Drive Files API).

می‌توانید همه «میاناهای برنامه‌سازی کاربردی Google» را امتحان کنید و دامنه‌های آن‌ها را در OAuth 2.0 Playground مشاهده کنید.

نمونه‌های HTTP GET

فراخوانی نقطه پایانی drive.files (میانای برنامه‌سازی کاربردی «فایل‌های Drive») بااستفاده از سرایند Authorization: Bearer HTTP ممکن است به‌شکل زیر باشد. توجه داشته باشید که باید کد دسترسی خودتان را مشخص کنید:

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

در اینجا فراخوانی برای همان میانای برنامه‌سازی کاربردی برای کاربر اصالت‌سنجی‌شده بااستفاده از پارامتر رشته پُرسمان access_token ارائه شده است:

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

‫curl مثال

می‌توانید این فرمان‌ها را با برنامه خط فرمان curl آزمایش کنید. در اینجا نمونه‌ای آورده شده است که از گزینه سرصفحه HTTP (ترجیحی) استفاده می‌کند:

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

یا، به‌طور جایگزین، گزینه پارامتر رشته پُرسمان:

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

نمونه کامل

مثال زیر فهرست فایل‌های Google Drive کاربر را در قالب JSON چاپ می‌کند، پس‌از اینکه کاربر اصالت‌سنجی می‌کند و به برنامه اجازه می‌دهد به فراداده Drive کاربر دسترسی داشته باشد.

PHP

برای اجرای این مثال:

  1. در «کنسول API»، نشانی وب ماشین محلی را به فهرست نشانی‌های وب هدایت مجدد اضافه کنید. برای مثال، http://localhost:8080 را اضافه کنید.
  2. فهرست راهنمای جدیدی ایجاد کنید و به آن بروید. برای مثال:
    mkdir ~/php-oauth2-example
    cd ~/php-oauth2-example
  3. کتابخانه کارخواه Google API برای PHP را بااستفاده از Composer نصب کنید:
    composer require google/apiclient:^2.15.0
  4. فایل‌های index.php و oauth2callback.php را با محتوای زیر ایجاد کنید.
  5. مثال را با سرور وب آزمایشی داخلی PHP اجرا کنید:
    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

این نمونه از چارچوب Flask استفاده می‌کند. این برنامه یک برنامه وب را در http://localhost:8080 اجرا می‌کند که به شما امکان می‌دهد جریان OAuth 2.0 را آزمایش کنید. اگر به آن نشانی وب بروید، باید پنج پیوند ببینید:

  • فراخوانی Drive API: این پیوند به صفحه‌ای اشاره می‌کند که تلاش می‌کند نمونه درخواست API را اجرا کند، درصورتی‌که کاربران اجازه را اعطا کرده باشند. درصورت لزوم، جریان صدور مجوز را شروع می‌کند. اگر موفقیت‌آمیز باشد، صفحه پاسخ میانای برنامه‌سازی کاربردی را نمایش می‌دهد.
  • صفحه ساختگی برای فراخوانی Calendar API: این پیوند به صفحه ساختگی‌ای اشاره می‌کند که تلاش می‌کند درخواست نمونه Calendar API را درصورت اعطای اجازه ازسوی کاربران اجرا کند. درصورت لزوم، جریان صدور مجوز را شروع می‌کند. درصورت موفقیت‌آمیز بودن، صفحه پاسخ API را نمایش می‌دهد.
  • جریان اصالت‌سنجی را مستقیماً آزمایش کنید: این پیوند به صفحه‌ای اشاره می‌کند که تلاش می‌کند کاربر را ازطریق جریان صدور مجوز ارسال کند. برنامه برای ارسال درخواست‌های مجاز «میانای برنامه‌سازی کاربردی» ازطرف کاربر اجازه می‌خواهد.
  • لغو اعتبارنامه‌های فعلی: این پیوند به صفحه‌ای اشاره می‌کند که اجازه‌هایی را که کاربر قبلاً به برنامه اعطا کرده است لغو می‌کند.
  • پاک کردن اطلاعات اعتباری جلسه Flask: این پیوند اطلاعات اعتباری مجوز را که در جلسه Flask ذخیره شده است پاک می‌کند. این ویژگی به شما امکان می‌دهد ببینید اگر کاربری که قبلاً به برنامه شما اجازه داده است در جلسه جدیدی درخواست API اجرا کند چه اتفاقی می‌افتد. همچنین به شما امکان می‌دهد پاسخ میانای برنامه‌سازی کاربردی را که برنامه‌تان درصورت لغو اجازه‌های اعطاشده به برنامه‌تان توسط کاربر دریافت می‌کند ببینید، و برنامه‌تان همچنان تلاش می‌کند درخواستی را با کد دسترسی لغوشده مجاز کند.
# -*- 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

این مثال از چارچوب Sinatra استفاده می‌کند.

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

برای اجرای این نمونه:

  1. در «کنسول API»، نشانی وب دستگاه محلی را به فهرست نشانی‌های وب تغییرمسیر اضافه کنید. برای مثال، http://localhost را اضافه کنید.
  2. مطمئن شوید که نسخه LTS نگهداری، LTS فعال، یا نسخه فعلی Node.js را نصب کرده‌اید.
  3. فهرست راهنمای جدیدی ایجاد کنید و به آن بروید. برای مثال:
    mkdir ~/nodejs-oauth2-example
    cd ~/nodejs-oauth2-example
  4. بااستفاده از npm، Google API Client Library برای Node.js را نصب کنید:
    npm install googleapis
  5. فایل‌های main.js را با محتوای زیر بسازید.
  6. نمونه را اجرا کنید:
    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

این نمونه Python از چارچوب Flask و کتابخانه Requests برای نمایش جریان وب OAuth 2.0 استفاده می‌کند. توصیه می‌کنیم برای این جریان از «کتابخانه کارخواه Google API برای Python» استفاده کنید. (مثال در برگه Python از کتابخانه مشتری استفاده می‌کند.)

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

قوانین اعتبارسنجی URI هدایت

Google قوانین اعتبارسنجی زیر را برای هدایت شناسه‌های URI اعمال می‌کند تا به توسعه‌دهندگان کمک کند برنامه‌هایشان را ایمن نگه دارند. URIهای تغییرمسیر شما باید از این قوانین پیروی کنند. برای تعریف دامنه، میزبان، مسیر، پُرسمان، طرح، و اطلاعات کاربر که در این قوانین استفاده می‌شود، به بخش ۳ «RFC 3986» مراجعه کنید.

قوانین اعتبارسنجی
طرح

URIهای تغییرمسیر باید از طرح HTTPS استفاده کنند، نه HTTP ساده. شناسه‌های منبع یکسان Localhost (ازجمله شناسه‌های منبع یکسان نشانی IP در localhost) از این قانون مستثنی هستند.

میزبان

میزبان‌ها نمی‌توانند نشانی‌های IP خام باشند. نشانی‌های IP میزبان محلی از این قانون مستثنی هستند.

دامنه
  • «دامنه‌های سطح بالای» میزبان (دامنه‌های سطح بالا) باید متعلق به فهرست پسوند عمومی باشد.
  • دامنه‌های میزبان نمی‌تواند “googleusercontent.com” باشد.
  • شناسه‌های منبع یکسان هدایت نمی‌توانند حاوی دامنه‌های کوتاه‌کننده نشانی وب (مثل goo.gl) باشند، مگراینکه برنامه مالک دامنه باشد. علاوه‌براین، اگر برنامه‌ای که مالک دامنه کوتاه کننده است تصمیم بگیرد به آن دامنه هدایت کند، آن نشانی وب هدایت باید یا حاوی “/google-callback/” در مسیر خود باشد یا با “/google-callback” پایان یابد.
  • Userinfo

    شناسه منبع یکسان تغییرمسیر نمی‌تواند حاوی زیرمؤلفه userinfo باشد.

    مسیر

    شناسه منبع یکسان (URI) تغییرمسیر نمی‌تواند حاوی پیمایش مسیر (که به آن بازگشت دایرکتوری نیز می‌گویند) باشد، که با “/..” یا “\..” یا کدبندی نشانی وب آن‌ها نشان داده می‌شود.

    پُرسمان

    نشانی‌های وب هدایت نباید حاوی هدایت‌های باز باشند.

    Fragment

    شناسه‌های منبع یکسان تغییرمسیر نمی‌توانند حاوی مؤلفه قطعه باشند.

    شخصیت‌ها شناسه منبع یکسان تغییرمسیر نمی‌تواند حاوی نویسه‌های خاصی باشد، ازجمله:
    • نویسه‌های عام ('*')
    • نویسه‌های ASCII چاپ‌نشدنی
    • کدبندی‌های درصد نامعتبر (هر کدبندی درصدی که از فرم کدبندی نشانی وب علامت درصد و به‌دنبال آن دو رقم مبنای شانزده پیروی نکند)
    • نویسه‌های تهی (نویسه تهی کدبندی‌شده، برای نمونه، %00، %C0%80)

    مجوزدهی افزایشی

    در پروتکل OAuth 2.0، برنامه شما برای دسترسی به منابعی که با گستره‌ها شناسایی می‌شوند، درخواست مجوز می‌کند. درخواست مجوز برای منابع در زمانی که به آن‌ها نیاز دارید، به‌عنوان بهترین رویه تجربه کاربری درنظر گرفته می‌شود. برای فعال کردن این روش، سرور مجوز Google از مجوز افزایشی پشتیبانی می‌کند. این ویژگی به شما امکان می‌دهد تا دامنه‌ها را درصورت نیاز درخواست کنید و، اگر کاربر اجازه را برای دامنه جدید اعطا کند، یک کد مجوز برمی‌گرداند که ممکن است با یک کد حاوی همه دامنه‌هایی که کاربر به پروژه اعطا کرده است مبادله شود.

    برای مثال، برنامه‌ای که به افراد امکان می‌دهد قطعه‌های موسیقی را نمونه‌برداری کنند و میکس بسازند ممکن است در زمان ورود به سیستم به منابع بسیار کمی نیاز داشته باشد، شاید فقط نام فردی که به سیستم وارد می‌شود. بااین‌حال، ذخیره کردن یک ترکیب کامل نیاز به دسترسی به Google Drive آن‌ها دارد. اکثر افراد اگر فقط زمانی که برنامه واقعاً به Google Drive نیاز دارد از آن‌ها درخواست دسترسی به آن شود، این کار را طبیعی می‌دانند.

    در این مورد، برنامه ممکن است در زمان ورود به سیستم، دامنه‌های openid و profile را برای انجام ورود به سیستم پایه درخواست کند، و سپس در زمان اولین درخواست برای ذخیره کردن ترکیب، دامنه https://www.googleapis.com/auth/drive.file را درخواست کند.

    برای پیاده‌سازی مجوز افزایشی، جریان عادی درخواست کد دسترسی را تکمیل می‌کنید اما مطمئن شوید که درخواست مجوز شامل محدوده‌هایی باشد که قبلاً اعطا شده است. این رویکرد به برنامه شما امکان می‌دهد از مدیریت چندین کد دسترسی اجتناب کند.

    قوانین زیر برای کد دسترسی به‌دست‌آمده از مجوز افزایشی اعمال می‌شود:

    • از این کد می‌توان برای دسترسی به منابع مربوط به هریک از دامنه‌هایی که در مجوز ترکیبی جدید گنجانده شده‌اند استفاده کرد.
    • وقتی از کد نوسازی برای مجوز ترکیبی استفاده می‌کنید تا کد دسترسی دریافت کنید، کد دسترسی نشان‌دهنده مجوز ترکیبی است و می‌تواند برای هریک از مقادیر scope موجود در پاسخ استفاده شود.
    • مجوز ترکیبی شامل همه دامنه‌هایی است که کاربر به پروژه میانای برنامه‌سازی کاربردی اعطا کرده است، حتی اگر این اعطاها از کارخواه‌های مختلف درخواست شده باشد. برای مثال، اگر کاربری بااستفاده از کلاینت رایانه برنامه به یک حوزه دسترسی اعطا کند و سپس حوزه دیگری را ازطریق کلاینت تلفن همراه به همان برنامه اعطا کند، مجوز ترکیبی شامل هر دو حوزه خواهد بود.
    • اگر توکنی را که نشان‌دهنده مجوز ترکیبی است لغو کنید، دسترسی به همه حوزه‌های آن مجوز ازطرف کاربر مرتبط به‌طور هم‌زمان لغو می‌شود.

    نمونه‌های کد مختص زبان در مرحله ۱: تنظیم کردن مجوز هدایت کردن به سرور OAuth 2.0 از Google همگی از مجوز افزایشی استفاده می‌کنند. نمونه کدهای زیر همچنین کدی را نشان می‌دهند که باید برای استفاده از مجوز افزایشی اضافه کنید.

    PHP

    $client->setIncludeGrantedScopes(true);

    Python

    در Python، آرگومان کلیدواژه include_granted_scopes را روی true تنظیم کنید تا مطمئن شوید که درخواست مجوز شامل محدوده‌هایی است که قبلاً اعطا شده است. بسیار محتمل است که include_granted_scopes تنها آرگومان کلیدواژه‌ای که تنظیم می‌کنید نباشد، همان‌طور که در مثال زیر نشان داده شده است.

    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

    بازآوری کد دسترسی (دسترسی آفلاین)

    کدهای دسترسی به‌طور دوره‌ای منقضی می‌شوند و به اطلاعات اعتباری نامعتبر برای درخواست API مربوطه تبدیل می‌شوند. اگر دسترسی آفلاین به گستره‌های مرتبط با کد دسترسی را درخواست کرده باشید، می‌توانید کد دسترسی را بدون درخواست اجازه از کاربر (ازجمله زمانی که کاربر حضور ندارد) بازآوری کنید.

    • اگر از «کتابخانه کارخواه Google API» استفاده می‌کنید، تا زمانی که شیء کارخواه را برای دسترسی آفلاین پیکربندی کنید، این شیء کد دسترسی را درصورت نیاز بازآوری می‌کند.
    • اگر از کتابخانه کارخواه استفاده نمی‌کنید، باید هنگام هدایت کاربر به سرور OAuth 2.0‏ Google، پارامتر پُرسمان HTTP‏ access_type را روی offline تنظیم کنید. در این حالت، سرور مجوز Google وقتی کد مجوز را با کد دسترسی مبادله می‌کنید، کد بازآوری برمی‌گرداند. سپس، اگر کد دسترسی منقضی شود (یا در هر زمان دیگری)، می‌توانید از کد بازآوری برای دریافت کد دسترسی جدید استفاده کنید.

    درخواست دسترسی آفلاین برای هر برنامه‌ای که نیاز به دسترسی به Google API دارد، زمانی که کاربر حضور ندارد، الزامی است. برای مثال، برنامه‌ای که خدمات پشتیبان‌گیری انجام می‌دهد یا کنش‌هایی را در زمان‌های ازپیش تعیین‌شده اجرا می‌کند باید بتواند وقتی کاربر حضور ندارد نشان دسترسی‌اش را بازآوری کند. سبک پیش‌فرض دسترسی online نام دارد.

    برنامه‌های وب سمت سرور، برنامه‌های نصب‌شده، و دستگاه‌ها همگی درطول فرایند صدور مجوز، ژتون بازآوری دریافت می‌کنند. معمولاً در برنامه‌های وب سمت کارخواه (جاوا اسکریپت) از نشان‌های بازآوری استفاده نمی‌شود.

    PHP

    اگر برنامه شما به دسترسی آفلاین به «میانای برنامه‌سازی کاربردی Google» نیاز دارد، نوع دسترسی کارخواه «میانای برنامه‌سازی کاربردی» را روی offline تنظیم کنید:

    $client->setAccessType("offline");

    پس‌از اینکه کاربر دسترسی آفلاین به دامنه‌های درخواستی را اعطا کرد، می‌توانید همچنان از کارخواه میانای برنامه‌سازی کاربردی برای دسترسی به میاناهای برنامه‌سازی کاربردی Google ازطرف کاربر در زمانی که کاربر آفلاین است استفاده کنید. شیء کارخواه کد دسترسی را درصورت نیاز بازآوری می‌کند.

    Python

    در Python، آرگومان کلیدواژه access_type را روی offline تنظیم کنید تا مطمئن شوید می‌توانید بدون نیاز به درخواست مجدد کاربر برای اجازه، رمز دسترسی را بازآوری کنید. بسیار محتمل است که access_type تنها شناسه کلیدواژه‌ای نباشد که تنظیم می‌کنید، همان‌طور که در مثال زیر نشان داده شده است.

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

    پس‌از اینکه کاربر دسترسی آفلاین به دامنه‌های درخواستی را اعطا کرد، می‌توانید همچنان از کارخواه میانای برنامه‌سازی کاربردی برای دسترسی به میاناهای برنامه‌سازی کاربردی Google ازطرف کاربر در زمانی که کاربر آفلاین است استفاده کنید. شیء کارخواه کد دسترسی را درصورت نیاز بازآوری می‌کند.

    Ruby

    اگر برنامه‌تان به دسترسی آفلاین به میانای برنامه‌سازی کاربردی Google نیاز دارد، نوع دسترسی کارخواه میانای برنامه‌سازی کاربردی را روی offline تنظیم کنید:

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

    پس‌از اینکه کاربر دسترسی آفلاین به دامنه‌های درخواستی را اعطا کرد، می‌توانید همچنان از کارخواه میانای برنامه‌سازی کاربردی برای دسترسی به میاناهای برنامه‌سازی کاربردی Google ازطرف کاربر در زمانی که کاربر آفلاین است استفاده کنید. شیء کارخواه کد دسترسی را درصورت نیاز بازآوری خواهد کرد.

    Node.js

    اگر برنامه شما به دسترسی آفلاین به «میانای برنامه‌سازی کاربردی Google» نیاز دارد، نوع دسترسی کارخواه «میانای برنامه‌سازی کاربردی» را روی offline تنظیم کنید:

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

    پس‌از اینکه کاربر دسترسی آفلاین به دامنه‌های درخواستی اعطا کرد، می‌توانید همچنان از کارخواه API برای دسترسی به «میاناهای برنامه‌سازی کاربردی Google» ازطرف کاربر در زمانی که کاربر آفلاین است استفاده کنید. شیء کارخواه کد دسترسی را درصورت نیاز بازآوری خواهد کرد.

    کدهای دسترسی منقضی می‌شوند. این کتابخانه به‌طور خودکار از یک ژتون بازآوری برای دریافت یک کد دسترسی جدید استفاده می‌کند، اگر کد دسترسی قبلی درحال انقضا باشد. روش آسان برای اطمینان از اینکه همیشه جدیدترین نشان‌ها را ذخیره می‌کنید استفاده از رویداد نشان‌ها است:

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

    این رویداد ژتون‌ها فقط در اولین مجوزدهی رخ می‌دهد و باید access_type را روی offline تنظیم کرده باشید تا هنگام فراخوانی روش generateAuthUrl، ژتون بازآوری را دریافت کنید. اگر قبلاً اجازه‌های لازم را به برنامه‌تان داده‌اید بدون اینکه محدودیت‌های مناسب را برای دریافت رمز بازآوری تنظیم کنید، باید برنامه را دوباره مجاز کنید تا رمز بازآوری جدیدی دریافت کند.

    برای تنظیم refresh_token در زمانی دیگر، می‌توانید از روش setCredentials استفاده کنید:

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

    وقتی کارخواه ژتون بازآوری داشته باشد، ژتون‌های دسترسی به‌طور خودکار در فراخوانی بعدی به API دریافت و بازآوری خواهند شد.

    HTTP/REST

    برای بازآوری کد دسترسی، برنامه‌تان درخواست HTTPS POST به سرور مجوز Google (https://oauth2.googleapis.com/token) ارسال می‌کند که شامل پارامترهای زیر در بدنه درخواست است:

    نام مقدار
    client_id شناسه کارخواه دریافت‌شده از کنسول API.
    client_secret اختیاری

    رمز کارخواه به‌دست‌آمده از کنسول API.

    grant_type همان‌طور که در مشخصات OAuth 2.0 تعریف شده است، مقدار این فیلد باید روی refresh_token تنظیم شود.
    refresh_token نماد بازآوری از تبادل کد مجوز برگردانده شد.

    اگرچه استفاده از DPoP اختیاری است، اما برای افزایش امنیت توصیه می‌شود. برای استفاده از DPoP با ژتون بازآوری، برنامه شما باید برای هر درخواست به نقطه پایانی ژتون، یک JWT اثبات DPoP جدید و منحصربه‌فرد تولید کند. این مدرک باید با همان کلید خصوصی‌ای امضا شود که درطول تبادل اولیه کد مجوز استفاده شده است. برنامه شما مدرک را به‌عنوان سرایند درخواست HTTP اضافه می‌کند.

    سرایند الزامی شرح
    DPoP اختیاری اثبات DPoP یک JWT است که مالکیت کلید خصوصی را اثبات می‌کند. این سرصفحه است، نه پارامتر. اگر ارائه شود، نشان‌های برگشتی به این کلید محدود می‌شوند. برای هر درخواست باید مدرک جدید و منحصربه‌فردی تولید شود و باید شامل ادعاهای htm (روش HTTP) و htu (شناسه منبع یکسان HTTP) باشد که با درخواست مطابقت داشته باشد.

    قطعه کد زیر یک درخواست نمونه را نشان می‌دهد:

    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 با کد بازآوری، باید یک مدرک DPoP جدید و منحصربه‌فرد JWT برای درخواست تولید کنید. برای دریافت دستورالعمل‌های گام‌به‌گام درباره تولید جفت کلید و ساختن JWT، به ساختن مدرک DPoP مراجعه کنید.

    تبادل موفق با پاسخ 200 OK حاوی یک کد دسترسی جدید نشان داده می‌شود. وقتی از DPoP استفاده می‌شود، token_type Bearer است. پاسخ موفقیت‌آمیز تأیید می‌کند که اثبات DPoP برای ژتون بازآوری پذیرفته شده است. Google همچنین ممکن است سرصفحه HTTP جدید DPoP-Nonce را در پاسخ برگرداند؛ درصورت برگردانده شدن، کارخواه شما باید این nonce را در حافظه نهان ذخیره کند و آن را در ادعای nonce اثبات DPoP در درخواست‌های بعدی لحاظ کند.

    اگر سرایند DPoP وجود نداشته باشد، نامعتبر باشد، یا از کلید نادرستی استفاده کند، تبادل ناموفق رخ می‌دهد. برای جزئیات مربوط به کدهای خطای خاص DPoP و مدیریت نانس‌ها، به تبادل ناموفق مراجعه کنید.

    تکه‌کد زیر نمونه‌ای از سرایندها و متن پاسخ موفقیت‌آمیز را هنگام استفاده از DPoP نشان می‌دهد:

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

    توجه داشته باشید که محدودیت‌هایی برای تعداد کدهای بازآوری صادرشده وجود دارد؛ یک محدودیت برای ترکیب کاربر/کارخواه، و محدودیت دیگر برای کاربر در همه کارخواه‌ها. باید کدهای بازآوری را در فضای ذخیره‌سازی بلندمدت ذخیره کنید و تا زمانی که معتبر هستند از آن‌ها استفاده کنید. اگر برنامه شما ژتون‌های بازآوری زیادی درخواست کند، ممکن است با این محدودیت‌ها مواجه شود که در این صورت ژتون‌های بازآوری قدیمی‌تر از کار خواهند افتاد.

    ابطال کد

    در برخی موارد، کاربر ممکن است بخواهد دسترسی اعطاشده به یک برنامه را لغو کند. کاربر می‌تواند با مراجعه به تنظیمات حساب، دسترسی را لغو کند. برای اطلاعات بیشتر، بخش برداشتن دسترسی سایت یا برنامه در سند پشتیبانی «برنامه‌ها و سایت‌های طرف سوم با امکان دسترسی به حساب شما» را ببینید.

    همچنین این امکان وجود دارد که برنامه به‌صورت برنامه‌نویسی‌شده دسترسی اعطاشده به آن را لغو کند. لغو برنامه‌ای در مواردی که کاربر اشتراک را لغو می‌کند، برنامه‌ای را برمی‌دارد، یا منابع API موردنیاز برنامه به‌طور قابل‌توجهی تغییر کرده است مهم است. به‌عبارت دیگر، بخشی از فرایند برداشتن محتوا می‌تواند شامل درخواست API برای اطمینان از برداشته شدن اجازه‌هایی باشد که قبلاً به برنامه داده شده است.

    PHP

    برای لغو کردن کد به‌صورت برنامه‌نویسی‌شده، با revokeToken() تماس بگیرید:

    $client->revokeToken();

    Python

    برای لغو کردن برنامه‌نویسی‌شده یک کد، درخواستی به https://oauth2.googleapis.com/revoke ارسال کنید که شامل کد به‌عنوان پارامتر باشد و سرصفحه Content-Type را تنظیم کند:

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

    Ruby

    برای لغو کردن برنامه‌نویسی‌شده یک توکن، یک درخواست HTTP به نقطه پایانی oauth2.revoke ارسال کنید:

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

    این ژتون می‌تواند ژتون دسترسی یا ژتون بازآوری باشد. اگر داده‌واحد کد دسترسی باشد و کد بازآوری متناظری داشته باشد، کد بازآوری نیز باطل خواهد شد.

    اگر لغو باموفقیت پردازش شود، رمز وضعیت پاسخ 200 است. برای شرایط خطا، رمز وضعیت 400 به‌همراه کد خطا برگردانده می‌شود.

    Node.js

    برای لغو کردن توکن به‌صورت برنامه‌نویسی، درخواست HTTPS POST به نقطه پایانی /revoke ارسال کنید:

    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();

    پارامتر ژتون می‌تواند ژتون دسترسی یا ژتون بازآوری باشد. اگر کد از نوع کد دسترسی باشد و کد بازآوری متناظر داشته باشد، کد بازآوری نیز باطل خواهد شد.

    اگر لغو باموفقیت پردازش شود، رمز وضعیت پاسخ 200 است. برای شرایط خطا، رمز وضعیت 400 به‌همراه کد خطا برگردانده می‌شود.

    HTTP/REST

    برای لغو کردن یک کد به‌صورت برنامه‌ریزی‌شده، برنامه شما درخواستی به https://oauth2.googleapis.com/revoke ارسال می‌کند و کد را به‌عنوان پارامتر اضافه می‌کند:

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

    کد می‌تواند کد دسترسی یا کد بازآوری باشد. اگر کد از نوع کد دسترسی باشد و کد بازآوری متناظر داشته باشد، کد بازآوری نیز باطل خواهد شد.

    اگر لغو با موفقیت پردازش شود، رمز وضعیت HTTP پاسخ 200 است. برای شرایط خطا، رمز وضعیت HTTP 400 به‌همراه کد خطا برگردانده می‌شود.

    دسترسی زمان‌محور

    دسترسی زمان‌محور به کاربر اجازه می‌دهد برای مدت محدودی به برنامه شما اجازه دسترسی به داده‌هایش را بدهد تا کنشی را تکمیل کند. دسترسی زمان‌محور در محصولات منتخب Google درطول جریان رضایت دردسترس است و به کاربران این امکان را می‌دهد که دسترسی را برای مدت محدودی اعطا کنند. یک نمونه از این ابزارها Data Portability API است که امکان انتقال یک‌باره داده‌ها را فراهم می‌کند.

    وقتی کاربری به برنامه شما دسترسی زمان‌دار می‌دهد، رمز بازآوری پس‌از مدت زمان مشخص منقضی می‌شود. توجه داشته باشید که ممکن است نشان‌های بازآوری تحت شرایط خاص زودتر نامعتبر شوند؛ برای جزئیات بیشتر، این موارد را ببینید. فیلد refresh_token_expires_in که در پاسخ تبادل کد مجوز برگردانده می‌شود، نشان‌دهنده زمان باقی‌مانده تا انقضای ژتون بازآوری در چنین مواردی است.

    پیاده‌سازی «محافظت بین‌حسابی»

    اقدام دیگری که باید برای محافظت از حساب‌های کاربرانتان انجام دهید، پیاده‌سازی «محافظت بین‌حسابی» بااستفاده از «سرویس محافظت بین‌حسابی» Google است. این سرویس به شما امکان می‌دهد در اعلان‌های رویداد امنیتی که اطلاعاتی درباره تغییرات عمده در حساب کاربر به برنامه شما ارائه می‌دهد مشترک شوید. سپس می‌توانید از این اطلاعات برای اقدام کردن براساس نحوه تصمیم‌گیری‌تان برای پاسخ دادن به رویدادها استفاده کنید.

    برخی‌از نمونه‌های انواع رویدادهایی که «سرویس محافظت بین‌حسابی» Google به برنامه‌تان ارسال می‌کند عبارت‌اند از:

    • 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

    برای کسب اطلاعات بیشتر درباره نحوه پیاده‌سازی «محافظت بین‌حسابی» و فهرست کامل رویدادهای دردسترس، به صفحه «محافظت از حساب‌های کاربری با محافظت بین‌حسابی» مراجعه کنید.