استخدام 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 هذا تحديدًا لتفويض المستخدم. وهي مصمَّمة للتطبيقات التي يمكنها تخزين معلومات سرية والحفاظ على الحالة. يمكن لتطبيق خادم ويب معتمد بشكل صحيح الوصول إلى واجهة برمجة تطبيقات أثناء تفاعل المستخدم مع التطبيق أو بعد أن يغادر المستخدم التطبيق.

تستخدم تطبيقات خادم الويب أيضًا حسابات الخدمة بشكل متكرر لتفويض طلبات واجهة برمجة التطبيقات، خاصةً عند استدعاء واجهات Cloud API للوصول إلى البيانات المستندة إلى المشاريع بدلاً من البيانات الخاصة بالمستخدمين. يمكن لتطبيقات خادم الويب استخدام حسابات الخدمة مع تفويض المستخدم.

مكتبات العملاء

تستخدم الأمثلة الخاصة باللغة الواردة في هذه الصفحة مكتبات عميل Google API لتنفيذ تفويض OAuth 2.0. لتشغيل نماذج الرموز البرمجية، عليك أولاً تثبيت مكتبة البرامج الخاصة بلغة الرمز البرمجي.

عند استخدام مكتبة برامج Google API للتعامل مع مسار OAuth 2.0 في تطبيقك، تنفّذ مكتبة البرامج العديد من الإجراءات التي كان على التطبيق تنفيذها بنفسه. على سبيل المثال، يحدّد هذا الإعداد الحالات التي يمكن فيها للتطبيق استخدام رموز الدخول المخزّنة أو إعادة تحميلها، بالإضافة إلى الحالات التي يجب فيها على التطبيق الحصول على الموافقة مجددًا. تنشئ مكتبة البرامج أيضًا عناوين URL صحيحة لإعادة التوجيه، وتساعد في تنفيذ معالجات إعادة التوجيه التي تستبدل رموز التفويض برموز الدخول المميزة.

تتوفّر مكتبات عملاء Google API للتطبيقات من جهة الخادم باللغات التالية:

المتطلبات الأساسية

تفعيل واجهات برمجة التطبيقات لمشروعك

يجب تفعيل واجهات Google APIs في API Consoleلأي تطبيق يستدعي هذه الواجهات.

لتفعيل واجهة برمجة تطبيقات لمشروعك، اتّبِع الخطوات التالية:

  1. Open the API Library في Google API Console
  2. If prompted, select a project, or create a new one.
  3. تعرض API Library جميع واجهات برمجة التطبيقات المتاحة، ويتم تجميعها حسب فئة المنتج ومدى رواجها. إذا لم يكن واجهة برمجة التطبيقات التي تريد تفعيلها ظاهرة في القائمة، استخدِم البحث للعثور عليها، أو انقر على عرض الكل في مجموعة المنتجات التي تنتمي إليها.
  4. اختَر واجهة برمجة التطبيقات التي تريد تفعيلها، ثم انقر على الزر تفعيل.
  5. If prompted, enable billing.
  6. If prompted, read and accept the API's Terms of Service.

إنشاء بيانات اعتماد التفويض

يجب أن يتضمّن أي تطبيق يستخدم OAuth 2.0 للوصول إلى Google APIs بيانات اعتماد تفويض تحدّد التطبيق لخادم OAuth 2.0 من Google. توضّح الخطوات التالية كيفية إنشاء بيانات اعتماد لمشروعك. يمكن لتطبيقاتك بعد ذلك استخدام بيانات الاعتماد للوصول إلى واجهات برمجة التطبيقات التي فعّلتها لهذا المشروع.

  1. Go to the Credentials page.
  2. انقر على إنشاء عميل.
  3. اختَر نوع التطبيق تطبيق الويب.
  4. املأ النموذج وانقر على إنشاء. يجب أن تحدّد التطبيقات التي تستخدم لغات وأُطر عمل مثل PHP وJava وPython وRuby و‎ .NET معرّفات موارد منتظمة (URI) لإعادة التوجيه معتمَدة. معرّفات الموارد المنتظمة (URI) لإعادة التوجيه هي نقاط النهاية التي يمكن لخادم OAuth 2.0 إرسال الردود إليها. يجب أن تلتزم نقاط النهاية هذه بقواعد التحقّق من الصحة في Google.

    للاختبار، يمكنك تحديد معرّفات URI تشير إلى الجهاز المحلي، مثل http://localhost:8080. مع أخذ ذلك في الاعتبار، يُرجى العلم أنّ جميع الأمثلة في هذا المستند تستخدم http://localhost:8080 كمعرّف الموارد المنتظم (URI) الخاص بإعادة التوجيه.

    ننصحك بتصميم نقاط نهاية المصادقة في تطبيقك بطريقة تضمن عدم عرض رموز التفويض لموارد أخرى على الصفحة.

بعد إنشاء بيانات الاعتماد، نزِّل الملف client_secret.json من API Console. احفظ الملف بشكل آمن في مكان لا يمكن لأي تطبيق آخر الوصول إليه.

تحديد نطاقات الوصول

تتيح النطاقات لتطبيقك طلب الوصول إلى الموارد التي يحتاجها فقط، كما تتيح للمستخدمين التحكّم في مقدار الوصول الذي يمنحونه لتطبيقك. وبالتالي، قد تكون هناك علاقة عكسية بين عدد النطاقات المطلوبة واحتمالية الحصول على موافقة المستخدم.

قبل البدء في تنفيذ تفويض OAuth 2.0، ننصحك بتحديد النطاقات التي سيحتاج تطبيقك إلى إذن للوصول إليها.

ننصح أيضًا بأن يطلب تطبيقك الوصول إلى نطاقات التفويض من خلال عملية تفويض متزايد، حيث يطلب تطبيقك الوصول إلى بيانات المستخدم في سياقها. تساعد هذه الممارسة المستخدمين على فهم سبب احتياج تطبيقك إلى الإذن الذي يطلبه.

يحتوي مستند نطاقات واجهة برمجة التطبيقات OAuth 2.0 على قائمة كاملة بالنطاقات التي يمكنك استخدامها للوصول إلى Google APIs.

المتطلبات الخاصة باللغة

لتشغيل أي من نماذج الرموز البرمجية الواردة في هذا المستند، يجب أن يكون لديك حساب على Google، وأن تتمكّن من الوصول إلى الإنترنت، وأن يتوفّر لديك متصفّح ويب. إذا كنت تستخدم إحدى مكتبات برامج واجهة برمجة التطبيقات، يمكنك أيضًا الاطّلاع على المتطلبات الخاصة باللغة أدناه.

PHP

لتشغيل نماذج رمز PHP في هذا المستند، ستحتاج إلى ما يلي:

  • الإصدار 8.0 من PHP أو إصدار أحدث مع تثبيت واجهة سطر الأوامر (CLI) وإضافة JSON
  • أداة إدارة التبعية Composer
  • مكتبة برامج Google APIs للغة PHP:

    composer require google/apiclient:^2.15.0

اطّلِع على مكتبة برامج Google API للغة PHP لمزيد من المعلومات.

Python

لتشغيل نماذج رموز Python البرمجية في هذا المستند، ستحتاج إلى ما يلي:

  • الإصدار 3.7 أو الإصدارات الأحدث من Python
  • أداة إدارة الحِزم pip
  • إصدار 2.0 من Google APIs Client Library للغة 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

راجِع ملاحظات الإصدار الخاصة بمكتبة برامج Google API Python إذا لم تتمكّن من ترقية Python ودليل النقل المرتبط بها.

Ruby

لتشغيل نماذج رموز Ruby البرمجية في هذا المستند، ستحتاج إلى ما يلي:

  • الإصدار 2.6 من Ruby أو إصدار أحدث
  • مكتبة Google Auth للغة Ruby:

    gem install googleauth
  • مكتبات البرامج لواجهات Google API الخاصة بخدمتَي Drive وCalendar:

    gem install google-apis-drive_v3 google-apis-calendar_v3
  • إطار عمل تطبيق الويب Sinatra Ruby

    gem install sinatra

Node.js

لتنفيذ عيّنات رمز Node.js في هذا المستند، ستحتاج إلى:

  • إصدار الصيانة أو الإصدار النشط أو الإصدار الحالي من 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. إذا منح المستخدم الأذونات المطلوبة، يسترد تطبيقك الرموز المميزة اللازمة لتقديم طلبات إلى واجهة برمجة التطبيقات نيابةً عن المستخدم.

الخطوة 1: ضبط مَعلمات التفويض

تتمثّل خطوتك الأولى في إنشاء طلب التفويض. يضبط هذا الطلب مَعلمات تحدّد تطبيقك وتعرّف الأذونات التي سيُطلب من المستخدم منحها لتطبيقك.

  • إذا كنت تستخدم مكتبة برامج عميل Google للمصادقة والتفويض باستخدام OAuth 2.0، عليك إنشاء عنصر وتكوينه لتحديد هذه المَعلمات.
  • إذا طلبت نقطة نهاية Google OAuth 2.0 مباشرةً، سيتم إنشاء عنوان URL وتحديد المَعلمات في عنوان URL هذا.

تحدّد علامات التبويب أدناه مَعلمات التفويض المتوافقة مع تطبيقات خادم الويب. توضّح الأمثلة الخاصة بكل لغة أيضًا كيفية استخدام مكتبة برامج أو مكتبة تفويض لإعداد عنصر يضبط هذه المَعلمات.

PHP

ينشئ مقتطف الرمز التالي عنصر Google\Client()، الذي يحدّد المَعلمات في طلب التفويض.

يستخدم هذا العنصر معلومات من ملف client_secret.json لتحديد تطبيقك. (يمكنك الاطّلاع على إنشاء بيانات اعتماد التفويض لمعرفة المزيد عن هذا الملف). يحدّد العنصر أيضًا النطاقات التي يطلب تطبيقك الإذن بالوصول إليها وعنوان URL لنقطة نهاية المصادقة في تطبيقك، والتي ستتعامل مع الردّ من خادم 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 الذي نزّلته بعد إنشاء بيانات اعتماد التفويض. يحدّد هذا العنصر أيضًا النطاقات التي يطلب تطبيقك الإذن بالوصول إليها وعنوان URL لنقطة نهاية المصادقة في تطبيقك، والتي ستتعامل مع الردّ من خادم 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 الذي أنشأته لإعداد عنصر عميل في تطبيقك. عند ضبط عنصر عميل، عليك تحديد النطاقات التي يحتاج تطبيقك إلى الوصول إليها، بالإضافة إلى عنوان URL لنقطة نهاية المصادقة في تطبيقك، والتي ستتعامل مع الردّ من خادم 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، مثل إنشاء عناوين URL لطلبات التفويض وتطبيق رموز الدخول المميزة على طلبات HTTP.

Node.js

ينشئ مقتطف الرمز التالي عنصر google.auth.OAuth2، الذي يحدّد المَعلمات في طلب التفويض.

يستخدم هذا العنصر معلومات من ملف client_secret.json لتحديد تطبيقك. لطلب أذونات من مستخدم لاسترداد رمز دخول، عليك إعادة توجيهه إلى صفحة موافقة. لإنشاء عنوان 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
 * 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

تتوفّر نقطة نهاية OAuth 2.0 من Google على https://accounts.google.com/o/oauth2/v2/auth. لا يمكن الوصول إلى نقطة النهاية هذه إلا عبر HTTPS. يتم رفض اتصالات HTTP العادية.

يتيح خادم التفويض من Google مَعلمات سلسلة طلب البحث التالية لتطبيقات خادم الويب:

المعلمات
client_id مطلوب

معرّف العميل لتطبيقك يمكنك العثور على هذه القيمة في .

redirect_uri مطلوب

تحدِّد هذه السمة المكان الذي يعيد خادم واجهة برمجة التطبيقات توجيه المستخدم إليه بعد إكماله عملية التفويض. يجب أن تتطابق القيمة تمامًا مع أحد معرّفات الموارد المنتظمة (URI) المسموح بها لإعادة التوجيه الخاصة بعميل OAuth 2.0 الذي أعددته في الخاص بعميلك. إذا لم تتطابق هذه القيمة مع معرّف الموارد المنتظم (URI) المصرّح به لإعادة التوجيه والمقدَّم 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 في مكوّن طلب البحث الخاص بعنوان URL (?) ضمن redirect_uri بعد أن يوافق المستخدم على طلب الوصول الذي يقدّمه تطبيقك أو يرفضه.

يمكنك استخدام هذه المَعلمة لعدّة أغراض، مثل توجيه المستخدم إلى المرجع الصحيح في تطبيقك، وإرسال أرقام عشوائية، والحدّ من التزوير في الطلبات الواردة من مواقع إلكترونية مختلفة. بما أنّه يمكن تخمين redirect_uri، فإنّ استخدام قيمة state يمكن أن يزيد من تأكّدك من أنّ الاتصال الوارد هو نتيجة لطلب مصادقة. إذا أنشأت سلسلة عشوائية أو ترميزًا لتجزئة ملف تعريف ارتباط أو قيمة أخرى تسجّل حالة العميل، يمكنك التحقّق من صحة الردّ لضمان أنّ الطلب والردّ نشآ في المتصفّح نفسه، ما يوفّر الحماية من هجمات مثل تزوير الطلبات على مستوى المواقع الإلكترونية. راجِع مستندات اتصال OpenID للاطّلاع على مثال حول كيفية إنشاء رمز مميّز من النوع state وتأكيده.

include_granted_scopes اختياريّ

تتيح هذه السمة للتطبيقات استخدام المصادقة المتزايدة لطلب الوصول إلى نطاقات إضافية حسب السياق. إذا ضبطت قيمة هذه المَعلمة على true وتمت الموافقة على طلب التفويض، سيشمل رمز الدخول الجديد أيضًا أي نطاقات سبق أن منح المستخدم التطبيق إذن الوصول إليها. يمكنك الاطّلاع على أمثلة في قسم التفويض التدريجي.

login_hint اختياريّ

إذا كان تطبيقك يعرف المستخدم الذي يحاول إثبات هويته، يمكنه استخدام هذه المَعلمة لتقديم تلميح إلى خادم مصادقة Google. يستخدم الخادم التلميح لتبسيط عملية تسجيل الدخول، إما عن طريق ملء حقل البريد الإلكتروني مسبقًا في نموذج تسجيل الدخول أو عن طريق اختيار جلسة تسجيل الدخول المتعدد المناسبة.

اضبط قيمة المَعلمة على عنوان بريد إلكتروني أو معرّف sub، وهو يساوي معرّف Google الخاص بالمستخدم.

prompt اختياريّ

قائمة حساسة لحالة الأحرف ومفصولة بمسافات تتضمّن الطلبات التي سيتم عرضها للمستخدم في حال عدم تحديد هذه المَعلمة، سيُطلب من المستخدم الإذن بالوصول إلى البيانات في المرة الأولى فقط التي يطلب فيها مشروعك الوصول إليها. يمكنك الاطّلاع على طلب إعادة الموافقة لمزيد من المعلومات.

القيم المحتملة هي:

none عدم عرض أي شاشات مصادقة أو موافقة يجب عدم تحديدها مع قيم أخرى.
consent يجب أن تطلب من المستخدم الموافقة.
select_account مطالبة المستخدم باختيار حساب

الخطوة 2: إعادة التوجيه إلى خادم OAuth 2.0 من Google

إعادة توجيه المستخدم إلى خادم OAuth 2.0 من Google لبدء عملية المصادقة والتفويض يحدث ذلك عادةً عندما يحتاج تطبيقك إلى الوصول إلى بيانات المستخدم لأول مرة. في حالة الموافقة المتزايدة، تحدث هذه الخطوة أيضًا عندما يحتاج تطبيقك لأول مرة إلى الوصول إلى موارد إضافية لا يملك إذن الوصول إليها بعد.

PHP

  1. إنشاء عنوان URL لطلب الوصول من خادم OAuth 2.0 من Google:
    $auth_url = $client->createAuthUrl();
  2. إعادة توجيه المستخدم إلى $auth_url:
    header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));

Python

يوضّح هذا المثال كيفية إعادة توجيه المستخدم إلى عنوان URL الخاص بالتفويض باستخدام إطار عمل تطبيق الويب Flask:

return flask.redirect(authorization_url)

Ruby

  1. إنشاء عنوان URL لطلب الوصول من خادم OAuth 2.0 من Google:
    auth_uri = authorizer.get_authorization_url(request: request)
  2. إعادة توجيه المستخدم إلى auth_uri

Node.js

  1. استخدِم عنوان URL الذي تم إنشاؤه authorizationUrl من طريقة الخطوة 1 generateAuthUrl لطلب الوصول من خادم OAuth 2.0 التابع لـ Google.
  2. إعادة توجيه المستخدم إلى authorizationUrl
    res.redirect(authorizationUrl);

HTTP/REST

مثال على إعادة التوجيه إلى خادم التفويض في Google

يظهر أدناه مثال على عنوان URL، مع فواصل أسطر ومسافات لتسهيل القراءة.

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//oauth2.example.com/code&
 client_id=client_id

بعد إنشاء عنوان URL للطلب، أعِد توجيه المستخدم إليه.

يصادق خادم OAuth 2.0 من Google على المستخدم ويحصل على موافقته ليتمكّن تطبيقك من الوصول إلى النطاقات المطلوبة. يتم إرسال الرد إلى تطبيقك باستخدام عنوان URL لإعادة التوجيه الذي حدّدته.

الخطوة 3: تطلب Google من المستخدم الموافقة

في هذه الخطوة، يقرّر المستخدم ما إذا كان سيمنح تطبيقك إذن الوصول المطلوب. في هذه المرحلة، يعرض Google نافذة موافقة تعرض اسم تطبيقك وخدمات Google API التي يطلب الإذن بالوصول إليها باستخدام بيانات اعتماد تفويض المستخدم وملخّصًا لنطاقات الوصول التي سيتم منحها. يمكن للمستخدم بعد ذلك الموافقة على منح إذن الوصول إلى نطاق واحد أو أكثر يطلبه تطبيقك أو رفض الطلب.

لا يحتاج تطبيقك إلى اتّخاذ أي إجراء في هذه المرحلة، إذ ينتظر الردّ من خادم OAuth 2.0 التابع لـ Google الذي يوضّح ما إذا تم منح أي إذن بالوصول. يتم توضيح هذا الرد في الخطوة التالية.

الأخطاء

قد تعرض الطلبات المُرسَلة إلى نقطة نهاية تفويض OAuth 2.0 من Google رسائل خطأ موجّهة إلى المستخدمين بدلاً من عمليات المصادقة والتفويض المتوقّعة. في ما يلي رموز الأخطاء الشائعة والحلول المقترَحة.

admin_policy_enforced

لا يمكن لحساب Google منح الإذن باستخدام نطاق واحد أو أكثر من النطاقات المطلوبة بسبب سياسات مشرف Google Workspace. راجِع مقالة المساعدة في "مشرف Google Workspace" بعنوان التحكّم في اختيار التطبيقات الخارجية والتطبيقات الداخلية التي يمكنها الوصول إلى بيانات Google Workspace لمزيد من المعلومات حول كيفية حظر المشرف للوصول إلى جميع النطاقات أو النطاقات الحسّاسة والمقيّدة إلى أن يتم منح إذن الوصول بشكل صريح إلى معرّف عميل OAuth.

disallowed_useragent

يتم عرض نقطة نهاية التفويض داخل وكيل مستخدم مضمّن غير مسموح به بموجب سياسات OAuth 2.0 من Google.

Android

قد تظهر رسالة الخطأ هذه لمطوّري تطبيقات Android عند فتح طلبات التفويض في android.webkit.WebView. على المطوّرين بدلاً من ذلك استخدام مكتبات Android، مثل تسجيل الدخول باستخدام حساب Google على Android أو AppAuth لنظام التشغيل Android من OpenID Foundation.

قد يواجه مطوّرو الويب هذا الخطأ عندما يفتح تطبيق Android رابطًا عامًا على الويب في وكيل مستخدم مضمّن، وينتقل المستخدم إلى نقطة نهاية تفويض بروتوكول OAuth 2.0 من Google من موقعك الإلكتروني. على المطوّرين السماح بفتح الروابط العامة في معالج الروابط التلقائي لنظام التشغيل، والذي يتضمّن كلاً من معالجات روابط تطبيقات Android أو تطبيق المتصفّح التلقائي. وتُعد مكتبة علامات التبويب المخصّصة في Android أيضًا خيارًا متاحًا.

iOS

قد يواجه مطوّرو تطبيقات iOS وmacOS هذا الخطأ عند فتح طلبات الحصول على إذن في WKWebView. على المطوّرين بدلاً من ذلك استخدام مكتبات iOS، مثل Google Sign-In for iOS أو AppAuth for iOS من OpenID Foundation.

قد يواجه مطوّرو الويب هذا الخطأ عندما يفتح تطبيق على iOS أو macOS رابط ويب عامًا في وكيل مستخدم مضمّن، وينتقِل المستخدم إلى نقطة نهاية تفويض بروتوكول OAuth 2.0 من Google من موقعك الإلكتروني. على المطوّرين السماح بفتح الروابط العامة في معالج الروابط التلقائي لنظام التشغيل، والذي يتضمّن معالجات الروابط العامة أو تطبيق المتصفّح التلقائي. وتُعد مكتبة SFSafariViewController خيارًا متاحًا أيضًا.

org_internal

إنّ رقم تعريف عميل OAuth في الطلب هو جزء من مشروع يحدّ من الوصول إلى حسابات Google في مؤسسة Google Cloud محدّدة. لمزيد من المعلومات حول خيار الإعداد هذا، راجِع قسم نوع المستخدم في مقالة المساعدة حول إعداد شاشة موافقة OAuth.

invalid_client

سر عميل OAuth غير صحيح. راجِع إعدادات عميل OAuth، بما في ذلك معرّف العميل وسر العميل المستخدَمَين في هذا الطلب.

deleted_client

تم حذف عميل OAuth المستخدَم لتقديم الطلب. يمكن أن تتم عملية الحذف يدويًا أو تلقائيًا في حالة العملاء غير النشطين . يمكن استعادة العملاء المحذوفين في غضون 30 يومًا من الحذف. مزيد من المعلومات

invalid_grant

عند إعادة تحميل رمز دخول أو استخدام التفويض التزايدي، قد تكون صلاحية الرمز المميز قد انتهت أو تم إبطاله. أثبِت هوية المستخدم مرة أخرى واطلب موافقته للحصول على رموز مميزة جديدة. إذا استمر ظهور هذا الخطأ، تأكَّد من إعداد تطبيقك بشكل صحيح ومن استخدام الرموز المميزة والمَعلمات الصحيحة في طلبك. بخلاف ذلك، قد يكون قد تم حذف حساب المستخدم أو إيقافه.

redirect_uri_mismatch

لا يتطابق redirect_uri الذي تم تمريره في طلب التفويض مع معرّف الموارد المنتظم (URI) لإعادة التوجيه المصرّح به لمعرّف عميل OAuth. راجِع معرّفات الموارد المنتظمة (URI) المعتمَدة لإعادة التوجيه في .

قد تشير المَعلمة redirect_uri إلى مسار OAuth خارج النطاق (OOB) الذي تم إيقافه نهائيًا ولم يعُد متاحًا. راجِع دليل نقل البيانات لتعديل عملية الدمج.

invalid_request

حدث خطأ في الطلب الذي قدّمته. قد يرجع ذلك إلى عدة أسباب:

  • لم يتم تنسيق الطلب بشكلٍ صحيح
  • لم يتضمّن الطلب المَعلمات المطلوبة
  • يستخدم الطلب طريقة لا تسمح بها Google لمنح إذن الوصول. التأكّد من أنّ عملية دمج OAuth تستخدم طريقة دمج مقترَحة

الخطوة 4: التعامل مع استجابة خادم OAuth 2.0

يستجيب خادم OAuth 2.0 لطلب الوصول الذي يرسله تطبيقك باستخدام عنوان URL المحدّد في الطلب.

إذا وافق المستخدم على طلب الوصول، سيتضمّن الردّ رمز تفويض. إذا لم يوافق المستخدم على الطلب، سيتضمّن الرد رسالة خطأ. يظهر رمز التفويض أو رسالة الخطأ التي يتم عرضها على خادم الويب في سلسلة طلب البحث، كما هو موضّح أدناه:

استجابة تتضمّن خطأ:

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

استجابة رمز التفويض:

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

نموذج استجابة خادم OAuth 2.0

يمكنك اختبار هذا المسار من خلال النقر على عنوان URL النموذجي التالي الذي يطلب إذنًا بالقراءة فقط لعرض البيانات الوصفية للملفات في 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//oauth2.example.com/code&
 client_id=client_id

بعد إكمال عملية OAuth 2.0، من المفترض أن تتم إعادة توجيهك إلى http://localhost/oauth2callback، ما سيؤدي على الأرجح إلى ظهور الخطأ 404 NOT FOUND ما لم يكن جهازك المحلي يعرض ملفًا على هذا العنوان. تقدّم الخطوة التالية تفاصيل أكثر حول المعلومات التي يتم عرضها في معرّف الموارد المنتظم (URI) عند إعادة توجيه المستخدم إلى تطبيقك.

الخطوة 5: تبديل رمز التفويض برموز مميّزة لإعادة التحميل والدخول

بعد أن يتلقّى خادم الويب رمز التفويض، يمكنه تبديل رمز التفويض برمز مميّز للوصول.

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

Ruby

في صفحة معاودة الاتصال، استخدِم مكتبة googleauth للتحقّق من ردّ خادم التفويض. استخدِم طريقة authorizer.handle_auth_callback_deferred لحفظ رمز التفويض وإعادة التوجيه إلى عنوان URL الذي طلب التفويض في الأصل. يؤجّل هذا الإجراء تبادل الرمز من خلال تخزين النتائج مؤقتًا في جلسة المستخدم.

  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 معرّف العميل الذي تم الحصول عليه من
client_secret سر العميل الذي تم الحصول عليه من
code رمز التفويض الذي تم عرضه في الطلب الأوّلي
grant_type وفقًا لما هو محدّد في مواصفات OAuth 2.0، يجب ضبط قيمة هذا الحقل على authorization_code.
redirect_uri أحد معرّفات الموارد المنتظمة (URI) لإعادة التوجيه المُدرَجة في مشروعك في لـ client_id المحدّد

يعرض المقتطف التالي نموذجًا لطلب:

POST /token HTTP/1.1
Host: oauth2.googleapis.com
Content-Type: application/x-www-form-urlencoded

code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7&
client_id=your_client_id&
client_secret=your_client_secret&
redirect_uri=https%3A//oauth2.example.com/code&
grant_type=authorization_code

تستجيب Google لهذا الطلب من خلال عرض عنصر JSON يحتوي على رمز مميز قصير الأمد للوصول ورمز مميز لإعادة التحميل. يُرجى العِلم أنّه لا يتم عرض رمز الدخول المميز إلا إذا ضبط تطبيقك المَعلمة access_type على offline في الطلب الأوّلي إلى خادم التفويض من Google.

يتضمّن الرد الحقول التالية:

الحقول
access_token الرمز المميز الذي يرسله تطبيقك للموافقة على طلب Google API.
expires_in تمثّل هذه السمة مدة صلاحية رمز الدخول المتبقية بالثواني.
refresh_token رمز مميّز يمكنك استخدامه للحصول على رمز مميّز جديد للوصول تكون رموز إعادة التحميل صالحة إلى أن يبطل المستخدم إذن الوصول أو تنتهي صلاحية رمز إعادة التحميل. مرة أخرى، لا يظهر هذا الحقل في الردّ إلا إذا ضبطت المَعلمة access_type على القيمة offline في الطلب الأوّلي إلى خادم التفويض من Google.
refresh_token_expires_in تعرض هذه السمة مدة صلاحية الرمز المميز لإعادة التحميل المتبقية بالثواني. لا يتم ضبط هذه القيمة إلا عندما يمنح المستخدم إذن الوصول المستند إلى الوقت.
scope نطاقات الوصول التي يمنحها access_token معبَّر عنها كقائمة من السلاسل الحساسة لحالة الأحرف والمفصولة بمسافات.
token_type تمثّل هذه السمة نوع الرمز المميّز الذي يتم عرضه. في الوقت الحالي، يتم دائمًا ضبط قيمة هذا الحقل على Bearer.

يعرض المقتطف التالي نموذجًا للردّ:

{
  "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 لطلب الموافقة من المستخدم مرة أخرى.

الخطوة 6: التحقّق من النطاقات التي منحها المستخدمون

عند طلب أذونات متعددة (نطاقات)، قد لا يمنح المستخدمون تطبيقك إذن الوصول إلى جميعها. يجب أن يتحقّق تطبيقك من النطاقات التي تم منحها فعليًا وأن يتعامل بشكل سليم مع الحالات التي يتم فيها رفض بعض الأذونات، وذلك عادةً عن طريق إيقاف الميزات التي تعتمد على تلك النطاقات المرفوضة.

ومع ذلك، هناك استثناءات. تتجاوز تطبيقات 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,
    'token_uri': credentials.token_uri,
    'client_id': credentials.client_id,
    'client_secret': credentials.client_secret,
    '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 APIs

PHP

استخدِم رمز الدخول لطلب بيانات من واجهات Google APIs من خلال إكمال الخطوات التالية:

  1. إذا كنت بحاجة إلى تطبيق رمز مميّز للوصول على عنصر Google\Client جديد، مثلاً إذا خزّنت رمز الوصول المميّز في جلسة مستخدم، استخدِم طريقة setAccessToken:
    $client->setAccessToken($access_token);
  2. أنشئ عنصر خدمة لواجهة برمجة التطبيقات التي تريد طلبها. يمكنك إنشاء عنصر خدمة من خلال توفير عنصر Google\Client معتمد إلى الدالة الإنشائية لواجهة برمجة التطبيقات التي تريد طلب بيانات منها. على سبيل المثال، لاستدعاء Drive API، اتّبِع الخطوات التالية:
    $drive = new Google\Service\Drive($client);
  3. إرسال طلبات إلى خدمة واجهة برمجة التطبيقات باستخدام الواجهة التي يوفّرها عنصر الخدمة على سبيل المثال، لإدراج الملفات في حساب Google Drive الخاص بالمستخدم الذي تمّت المصادقة عليه:
    $files = $drive->files->listFiles(array());

Python

بعد الحصول على رمز دخول، يمكن لتطبيقك استخدام هذا الرمز لتفويض طلبات واجهة برمجة التطبيقات نيابةً عن حساب مستخدم أو حساب خدمة معيّن. استخدِم بيانات اعتماد التفويض الخاصة بالمستخدم لإنشاء عنصر خدمة لواجهة برمجة التطبيقات التي تريد طلب بيانات منها، ثم استخدِم هذا العنصر لتقديم طلبات بيانات معتمَدة من واجهة برمجة التطبيقات.

  1. أنشئ عنصر خدمة لواجهة برمجة التطبيقات التي تريد طلبها. يمكنك إنشاء عنصر خدمة من خلال استدعاء طريقة build في مكتبة googleapiclient.discovery مع اسم واجهة برمجة التطبيقات وإصدارها وبيانات اعتماد المستخدم: على سبيل المثال، لاستدعاء الإصدار 3 من Drive API:
    from googleapiclient.discovery import build
    
    drive = build('drive', 'v2', credentials=credentials)
  2. إرسال طلبات إلى خدمة واجهة برمجة التطبيقات باستخدام الواجهة التي يوفّرها عنصر الخدمة على سبيل المثال، لإدراج الملفات في حساب Google Drive الخاص بالمستخدم الذي تمّت المصادقة عليه:
    files = drive.files().list().execute()

Ruby

بعد الحصول على رمز دخول، يمكن لتطبيقك استخدام هذا الرمز لتقديم طلبات إلى واجهة برمجة التطبيقات نيابةً عن حساب مستخدم أو حساب خدمة معيّن. استخدِم بيانات اعتماد التفويض الخاصة بالمستخدم لإنشاء عنصر خدمة لواجهة برمجة التطبيقات التي تريد طلب بيانات منها، ثم استخدِم هذا العنصر لتقديم طلبات بيانات معتمَدة من واجهة برمجة التطبيقات.

  1. أنشئ عنصر خدمة لواجهة برمجة التطبيقات التي تريد طلبها. على سبيل المثال، لاستدعاء الإصدار 3 من 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. يمكن لتطبيقك استخدام هذا الرمز لتفويض طلبات واجهة برمجة التطبيقات نيابةً عن حساب مستخدم أو حساب خدمة معيّن. أنشئ عنصر خدمة لواجهة برمجة التطبيقات التي تريد طلبها. على سبيل المثال، يستخدم الرمز التالي 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 نيابةً عن حساب مستخدم معيّن إذا تم منح نطاقات الوصول التي تتطلّبها واجهة برمجة التطبيقات. لإجراء ذلك، يجب تضمين رمز الدخول في طلب إلى واجهة برمجة التطبيقات من خلال تضمين مَعلمة طلب بحث access_token أو قيمة Bearer في عنوان HTTP Authorization. عند الإمكان، من الأفضل استخدام عنوان HTTP لأنّ سلاسل طلب البحث تكون عادةً مرئية في سجلات الخادم. في معظم الحالات، يمكنك استخدام مكتبة برامج العميل لإعداد طلباتك إلى واجهات Google API (على سبيل المثال، عند طلب Drive Files API).

يمكنك تجربة جميع واجهات Google APIs والاطّلاع على نطاقاتها في مساحة بروتوكول OAuth 2.0.

أمثلة على طلبات HTTP GET

قد يبدو طلب إلى نقطة النهاية drive.files (واجهة برمجة التطبيقات Drive Files API) باستخدام عنوان HTTP Authorization: Bearer على النحو التالي. يُرجى العِلم أنّه عليك تحديد رمز الدخول الخاص بك:

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

مثال كامل

يطبع المثال التالي قائمة بالملفات بتنسيق JSON في Google Drive الخاص بالمستخدم بعد أن يصادق المستخدم على التطبيق ويمنحه الموافقة على الوصول إلى البيانات الوصفية الخاصة به في Drive.

PHP

لتشغيل هذا المثال:

  1. في API Console، أضِف عنوان URL الخاص بالجهاز المحلي إلى قائمة عناوين URL لإعادة التوجيه، مثلاً، أضِف 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. إذا انتقلت إلى عنوان URL هذا، من المفترض أن تظهر لك خمسة روابط:

  • طلب بيانات من Drive API: يشير هذا الرابط إلى صفحة تحاول تنفيذ نموذج لطلب بيانات من واجهة برمجة التطبيقات إذا منح المستخدمون الإذن بذلك. يبدأ مسار التفويض إذا لزم الأمر. في حال نجاح ذلك، ستعرض الصفحة استجابة واجهة برمجة التطبيقات.
  • صفحة تجريبية لطلب بيانات من Calendar API: يشير هذا الرابط إلى صفحة تجريبية تحاول تنفيذ طلب بيانات نموذجي من Calendar API إذا منح المستخدمون الإذن بذلك. إذا لزم الأمر، يبدأ مسار التفويض. في حال نجاح ذلك، ستعرض الصفحة استجابة واجهة برمجة التطبيقات.
  • اختبار مسار المصادقة مباشرةً: يشير هذا الرابط إلى صفحة تحاول توجيه المستخدم خلال مسار المصادقة. يطلب التطبيق الإذن بتقديم طلبات إلى واجهة برمجة التطبيقات نيابةً عن المستخدم.
  • إبطال بيانات الاعتماد الحالية: يشير هذا الرابط إلى صفحة تبطل الأذونات التي سبق أن منحها المستخدم للتطبيق.
  • محو بيانات اعتماد جلسة Flask: يؤدي هذا الرابط إلى محو بيانات اعتماد التفويض المخزّنة في جلسة Flask. يتيح لك ذلك معرفة ما سيحدث إذا حاول مستخدم سبق له منح الإذن لتطبيقك تنفيذ طلب واجهة برمجة تطبيقات في جلسة جديدة. تتيح لك هذه الأداة أيضًا الاطّلاع على استجابة واجهة برمجة التطبيقات التي سيحصل عليها تطبيقك إذا ألغى المستخدم الأذونات الممنوحة لتطبيقك، وحاول تطبيقك مع ذلك تفويض طلب باستخدام رمز دخول تم إبطاله.
# -*- coding: utf-8 -*-

import os
import flask
import requests

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

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

# 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 credentials from the session.
    credentials = google.oauth2.credentials.Credentials(
        **flask.session['credentials'])

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

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

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

    return flask.jsonify(**files)
  else:
    # User didn't authorize read-only Drive activity permission.
    # Update UX and application accordingly
    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.')

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

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

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

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

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

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

  # 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 Console، أضِف عنوان URL الخاص بالجهاز المحلي إلى قائمة عناوين URL لإعادة التوجيه. على سبيل المثال، أضِف http://localhost.
  2. تأكَّد من تثبيت إصدار LTS للصيانة أو إصدار LTS نشط أو الإصدار الحالي من Node.js.
  3. أنشئ دليلاً جديدًا وانتقِل إليه. على سبيل المثال:
    mkdir ~/nodejs-oauth2-example
    cd ~/nodejs-oauth2-example
  4. ثبِّت مكتبة برامج Google API Client لنظام التشغيل Node.js باستخدام npm:
    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 Client Library للغة 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 لإعادة التوجيه لمساعدة المطوّرين في الحفاظ على أمان تطبيقاتهم. يجب أن تلتزم معرّفات الموارد الموحّدة لإعادة التوجيه بالقواعد التالية. راجِع القسم 3 من RFC 3986 للتعرّف على تعريفات النطاق والمضيف والمسار والاستعلام والمخطط وuserinfo المذكورة أدناه.

قواعد التحقّق من الصحة
المخطط

يجب أن تستخدم معرّفات الموارد المنتظمة (URI) لإعادة التوجيه مخطط HTTPS، وليس HTTP العادي. يُستثنى من هذه القاعدة معرّفات الموارد المنتظمة (URI) الخاصة بالمضيف المحلي (بما في ذلك معرّفات الموارد المنتظمة (URI) الخاصة بعنوان IP الخاص بالمضيف المحلي).

المضيف

لا يمكن أن تكون المضيفات عناوين IP أولية. يتم استثناء عناوين IP الخاصة بالمضيف المحلي من هذه القاعدة.

النطاق
  • يجب أن تنتمي نطاقات المستوى الأعلى الخاصة بالمضيف (Top Level Domains) إلى قائمة اللاحقات العلنية.
  • لا يمكن أن تكون نطاقات المضيف “googleusercontent.com”.
  • لا يمكن أن تحتوي معرّفات URI لإعادة التوجيه على نطاقات مختصرة لعنوان URL (مثل goo.gl) ما لم يكن التطبيق يملك النطاق. بالإضافة إلى ذلك، إذا اختار تطبيق يملك نطاقًا مختصرًا إعادة التوجيه إلى هذا النطاق، يجب أن يحتوي معرّف الموارد المنتظم لإعادة التوجيه على “/google-callback/” في مساره أو ينتهي بـ “/google-callback”.
  • Userinfo

    لا يمكن أن تحتوي معرّفات الموارد المنتظمة لإعادة التوجيه على المكوّن الفرعي userinfo.

    المسار

    يجب ألا تحتوي معرّفات URI لإعادة التوجيه على ثغرة path traversal (تُعرف أيضًا باسم directory backtracking)، والتي يمثّلها الرمز “/..” أو “\..” أو ترميز عنوان URL الخاص بهما.

    طلب بحث

    لا يمكن أن تحتوي معرّفات الموارد المنتظمة (URI) لإعادة التوجيه على عمليات إعادة توجيه مفتوحة.

    الجزء

    لا يمكن أن تحتوي معرّفات URI لإعادة التوجيه على مكوّن الجزء.

    الشخصيات لا يمكن أن تحتوي معرّفات URI لإعادة التوجيه على أحرف معيّنة، بما في ذلك:
    • أحرف البدل ('*')
    • أحرف ASCII غير قابلة للطباعة
    • عمليات ترميز غير صالحة بنسبة مئوية (أي عملية ترميز بنسبة مئوية لا تتّبع شكل ترميز عنوان URL الذي يتضمّن علامة النسبة المئوية متبوعة برقمين سداسيين عشريين)
    • الأحرف الفارغة (حرف NULL مشفّر، مثل %00, %C0%80)

    تفويض تدريجي

    في بروتوكول OAuth 2.0، يطلب تطبيقك الحصول على إذن بالوصول إلى الموارد التي يتم تحديدها من خلال النطاقات. يُعدّ طلب الحصول على إذن بالوصول إلى الموارد في الوقت الذي تحتاجها فيه من أفضل ممارسات تجربة المستخدم. ولتفعيل هذه الممارسة، يتيح خادم التفويض من Google التفويض التدريجي. تتيح لك هذه الميزة طلب النطاقات حسب الحاجة، وإذا منح المستخدم الإذن بالنطاق الجديد، سيتم عرض رمز تفويض يمكن استبداله برمز مميز يتضمّن جميع النطاقات التي منحها المستخدم للمشروع.

    على سبيل المثال، قد يحتاج تطبيق يتيح للمستخدمين الاستماع إلى عيّنات من المقاطع الموسيقية وإنشاء مزيج منها إلى عدد قليل جدًا من الموارد عند تسجيل الدخول، ربما لا يحتاج إلى أكثر من اسم المستخدم الذي يسجّل الدخول. ومع ذلك، يتطلّب حفظ أغنية معدَّلة مكتملة الوصول إلى حساب Google Drive. سيبدو الأمر طبيعيًا لمعظم المستخدمين إذا طُلب منهم منح التطبيق إذن الوصول إلى Google Drive فقط عندما يحتاج التطبيق إلى ذلك.

    في هذه الحالة، قد يطلب التطبيق النطاقَين openid وprofile عند تسجيل الدخول لإجراء عملية تسجيل الدخول الأساسية، ثم يطلب النطاق https://www.googleapis.com/auth/drive.file لاحقًا عند إجراء الطلب الأول لحفظ أغنية مختلطة.

    لتنفيذ التفويض التدريجي، عليك إكمال المسار العادي لطلب رمز مميز للوصول، ولكن تأكَّد من أنّ طلب التفويض يتضمّن النطاقات التي تم منحها سابقًا. تتيح هذه الطريقة لتطبيقك تجنُّب الحاجة إلى إدارة رموز وصول متعددة.

    تنطبق القواعد التالية على رمز الدخول الذي تم الحصول عليه من تفويض تدريجي:

    • يمكن استخدام الرمز المميز للوصول إلى الموارد التي تتوافق مع أي من النطاقات المضمّنة في التفويض الجديد المدمج.
    • عند استخدام الرمز المميز لإعادة التحميل للحصول على رمز دخول من خلال التفويض المجمّع، يمثّل رمز الدخول التفويض المجمّع ويمكن استخدامه لأي من قيم scope المضمّنة في الرد.
    • يتضمّن التفويض المجمّع جميع النطاقات التي منحها المستخدم لمشروع واجهة برمجة التطبيقات، حتى إذا تم طلب منحها من برامج عملاء مختلفة. على سبيل المثال، إذا منح مستخدم إذن الوصول إلى نطاق واحد باستخدام برنامج تطبيق على الكمبيوتر المكتبي، ثم منح نطاقًا آخر للتطبيق نفسه من خلال برنامج تطبيق على الجهاز الجوّال، سيشمل التفويض المجمّع كلا النطاقين.
    • في حال إبطال رمز مميّز يمثّل تفويضًا مجمّعًا، سيتم إبطال إذن الوصول إلى جميع نطاقات هذا التفويض نيابةً عن المستخدم المرتبط به في الوقت نفسه.

    تستخدم جميع نماذج الرموز الخاصة باللغة في الخطوة 1: ضبط مَعلمات التفويض وعيّنة عنوان URL لإعادة التوجيه HTTP/REST في الخطوة 2: إعادة التوجيه إلى خادم 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//oauth2.example.com/code&
      prompt=consent&
      include_granted_scopes=true

    إعادة تحميل رمز الدخول (الوصول بدون اتصال بالإنترنت)

    تنتهي صلاحية رموز الدخول بشكل دوري وتصبح بيانات اعتماد غير صالحة لطلب بيانات من واجهة برمجة التطبيقات ذات الصلة. يمكنك إعادة تحميل رمز الدخول بدون مطالبة المستخدم بالحصول على إذن (حتى عندما لا يكون المستخدم متوفّرًا) إذا طلبت الوصول بلا إنترنت إلى النطاقات المرتبطة بالرمز.

    • في حال استخدام إحدى مكتبات عميل Google API، يعيد كائن العميل تحديث رمز الدخول حسب الحاجة طالما أنّك ضبطت هذا الكائن على إمكانية الوصول بلا إنترنت.
    • إذا كنت لا تستخدم مكتبة برامج للعملاء، عليك ضبط مَعلمة طلب البحث access_type HTTP على offline عند إعادة توجيه المستخدم إلى خادم OAuth 2.0 من Google. في هذه الحالة، يعرض خادم التفويض من Google رمزًا مميزًا لإعادة التحميل عند تبديل رمز التفويض برمز دخول. بعد ذلك، إذا انتهت صلاحية رمز الدخول (أو في أي وقت آخر)، يمكنك استخدام رمز مميّز لإعادة التحميل للحصول على رمز دخول جديد.

    يُعدّ طلب الوصول بلا إنترنت شرطًا أساسيًا لأي تطبيق يحتاج إلى الوصول إلى واجهة Google API عندما لا يكون المستخدم متوفّرًا. على سبيل المثال، يجب أن يتمكّن تطبيق يقدّم خدمات احتياطية أو ينفّذ إجراءات في أوقات محدّدة مسبقًا من إعادة تحميل رمز الدخول عندما لا يكون المستخدم متواجدًا. يُطلق على النمط التلقائي للوصول اسم online.

    تحصل تطبيقات الويب من جهة الخادم والتطبيقات المثبَّتة والأجهزة على رموز مميزة لإعادة التحميل أثناء عملية التفويض. لا تُستخدم رموز التحديث عادةً في تطبيقات الويب التي تعمل من جهة العميل (JavaScript).

    PHP

    إذا كان تطبيقك يحتاج إلى الوصول إلى إحدى واجهات Google API بدون اتصال بالإنترنت، اضبط نوع الوصول إلى عميل واجهة برمجة التطبيقات على offline:

    $client->setAccessType("offline");

    بعد أن يمنح المستخدم إذن الوصول بلا إنترنت إلى النطاقات المطلوبة، يمكنك مواصلة استخدام برنامج واجهة برمجة التطبيقات للوصول إلى Google APIs بالنيابة عن المستخدم عندما يكون غير متصل بالإنترنت. سيُعيد عنصر العميل تحميل رمز الدخول المميز حسب الحاجة.

    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 APIs بالنيابة عن المستخدم عندما يكون غير متصل بالإنترنت. سيُعيد عنصر العميل تحميل رمز الدخول المميز حسب الحاجة.

    Ruby

    إذا كان تطبيقك يحتاج إلى الوصول إلى إحدى واجهات Google API بدون اتصال بالإنترنت، اضبط نوع الوصول إلى عميل واجهة برمجة التطبيقات على offline:

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

    بعد أن يمنح المستخدم إذن الوصول بلا إنترنت إلى النطاقات المطلوبة، يمكنك مواصلة استخدام برنامج واجهة برمجة التطبيقات للوصول إلى Google APIs بالنيابة عن المستخدم عندما يكون غير متصل بالإنترنت. سيُعيد عنصر العميل تحميل رمز الدخول المميز حسب الحاجة.

    Node.js

    إذا كان تطبيقك يحتاج إلى الوصول إلى إحدى واجهات Google API بدون اتصال بالإنترنت، اضبط نوع الوصول إلى عميل واجهة برمجة التطبيقات على 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
    });

    بعد أن يمنح المستخدم إذن الوصول بلا إنترنت إلى النطاقات المطلوبة، يمكنك مواصلة استخدام برنامج واجهة برمجة التطبيقات للوصول إلى Google APIs بالنيابة عن المستخدم عندما يكون غير متصل بالإنترنت. سيُعيد عنصر العميل تحميل رمز الدخول المميز حسب الحاجة.

    تنتهي صلاحية رموز الدخول. ستستخدم هذه المكتبة تلقائيًا رمزًا مميزًا لإعادة التحميل من أجل الحصول على رمز مميز جديد للوصول إذا كان على وشك انتهاء صلاحيته. للتأكّد من تخزين أحدث الرموز المميّزة دائمًا، يمكنك استخدام حدث الرموز المميّزة:

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

    بعد حصول العميل على رمز مميز لإعادة التحميل، سيتم الحصول على رموز الدخول وإعادة تحميلها تلقائيًا في الاتصال التالي بواجهة برمجة التطبيقات.

    HTTP/REST

    لتحديث رمز الدخول، يرسل تطبيقك طلب HTTPS POST إلى خادم التفويض في Google (https://oauth2.googleapis.com/token) يتضمّن المَعلمات التالية:

    الحقول
    client_id معرّف العميل الذي تم الحصول عليه من API Console.
    client_secret سرّ العميل الذي تم الحصول عليه من API Console.
    grant_type كما هو محدّد في مواصفات OAuth 2.0، يجب ضبط قيمة هذا الحقل على refresh_token.
    refresh_token الرمز المميز لإعادة التحميل الذي تم عرضه من عملية تبديل رمز التفويض

    يعرض المقتطف التالي نموذجًا لطلب:

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

    ما دام المستخدم لم يبطل إذن الوصول الممنوح للتطبيق، سيعرض خادم الرموز المميزة عنصر JSON يتضمّن رمزًا مميزًا جديدًا للوصول. يعرض المقتطف التالي نموذجًا لردّ:

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

    يُرجى العِلم أنّ هناك حدودًا لعدد رموز التحديث التي سيتم إصدارها، وهي حدّ واحد لكل مجموعة من العملاء والمستخدمين، وحدّ آخر لكل مستخدم على مستوى جميع العملاء. عليك حفظ رموز إعادة التحميل في مساحة تخزين طويلة الأمد ومواصلة استخدامها طالما أنّها تظل صالحة. إذا كان تطبيقك يطلب عددًا كبيرًا جدًا من رموز التحديث، قد يواجه هذه الحدود، وفي هذه الحالة سيتوقف عمل رموز التحديث الأقدم.

    إبطال رمز مميّز

    في بعض الحالات، قد يرغب المستخدم في إبطال إذن الوصول الذي تم منحه لتطبيق. يمكن للمستخدم إبطال إذن الوصول من خلال الانتقال إلى إعدادات الحساب. للحصول على مزيد من المعلومات، يمكنك الاطّلاع على قسم إزالة إمكانية وصول موقع إلكتروني أو تطبيق في مستند الدعم "المواقع الإلكترونية والتطبيقات الخارجية التي يمكنها الوصول إلى حسابك".

    من الممكن أيضًا أن يلغي تطبيق إذن الوصول الذي تم منحه له بشكل آلي. ويكون الإبطال آليًا مهمًا في الحالات التي يلغي فيها المستخدم اشتراكه أو يزيل تطبيقًا أو تتغير فيها بشكل كبير موارد واجهة برمجة التطبيقات التي يتطلبها التطبيق. بعبارة أخرى، يمكن أن يتضمّن جزء من عملية الإزالة طلبًا من خلال واجهة برمجة التطبيقات لضمان إزالة الأذونات التي تم منحها للتطبيق سابقًا.

    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

    يمكنك الاطّلاع على صفحة حماية حسابات المستخدمين باستخدام ميزة "الحماية العابرة للحساب" للحصول على مزيد من المعلومات حول كيفية تنفيذ ميزة "الحماية العابرة للحساب" والقائمة الكاملة بالأحداث المتاحة.