OAuth 2.0 لتطبيقات الويب من جهة العميل

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

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

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

مكتبة برامج Google APIs و"خدمات هوية Google"

إذا كنت تستخدم مكتبة برامج Google APIs للغة JavaScript لإجراء طلبات معتمَدة إلى Google، عليك استخدام مكتبة JavaScript Google Identity Services لمعالجة عملية التفويض. ننصح بشدة باستخدام نموذج الرمز في "خدمات هوية Google"، والذي يستند إلى مسار رمز التفويض الأكثر أمانًا مع PKCE.

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

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

يجب أن يفعّل أي تطبيق يطلب بيانات من Google APIs واجهات برمجة التطبيقات هذه في "وحدة تحكّم واجهة برمجة التطبيقات".

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

  1. افتح مكتبة واجهات برمجة التطبيقات في Google API Console.
  2. اختَر مشروعًا أو أنشِئ مشروعًا جديدًا إذا طُلب منك ذلك.
  3. تعرض "مكتبة واجهة برمجة التطبيقات" جميع واجهات برمجة التطبيقات المتاحة، مجمّعة حسب مجموعة المنتجات ومدى رواجها. إذا لم تظهر واجهة برمجة التطبيقات التي تريد تفعيلها في القائمة، استخدِم البحث للعثور عليها، أو انقر على عرض الكل في مجموعة المنتجات التي تنتمي إليها.
  4. اختَر واجهة برمجة التطبيقات التي تريد تفعيلها، ثم انقر على الزر تفعيل.
  5. فعِّل الفوترة إذا طُلب منك ذلك.
  6. اقرأ بنود خدمة واجهة برمجة التطبيقات ووافِق عليها إذا طُلب منك ذلك.

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

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

  1. انتقِل إلى صفحة "العملاء".
  2. انقر على إنشاء عميل (Create Client).
  3. اختَر نوع التطبيق تطبيق ويب.
  4. أكمل النموذج. يجب أن تحدّد التطبيقات التي تستخدم JavaScript لإرسال طلبات بيانات من واجهة برمجة التطبيقات معتمَدة من Google APIs مصادر JavaScript المعتمَدة. تحدّد المصادر النطاقات التي يمكن لتطبيقك إرسال الطلبات منها إلى خادم OAuth 2.0. يجب أن تلتزم هذه المصادر بقواعد التحقّق من الصحة في Google.

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

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

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

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

الحصول على رموز الدخول عبر OAuth 2.0

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

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

لطلب الإذن بالوصول إلى بيانات المستخدم، عليك إعادة توجيه المستخدم إلى خادم OAuth 2.0 من Google.

نقاط نهاية OAuth 2.0

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

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

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

معرّف العميل لتطبيقك يمكنك العثور على هذه القيمة في صفحة "العملاء" ضمن Cloud Console.

redirect_uri مطلوب

يحدّد هذا المَعلمة المكان الذي يعيد خادم واجهة برمجة التطبيقات توجيه المستخدم إليه بعد أن يكمل المستخدم عملية التفويض. يجب أن تتطابق القيمة تمامًا مع أحد عناوين URI لإعادة التوجيه المصرّح بها لعميل OAuth 2.0، والتي تم ضبطها في صفحة العملاء في Cloud Console الخاصة بالعميل. إذا لم تتطابق هذه القيمة مع معرّف موارد منتظم (URI) معتمَد لإعادة التوجيه لـ client_id المقدَّم، سيظهر لك الخطأ redirect_uri_mismatch.

يُرجى العِلم أنّ المخطط http أو https وحالة الأحرف والشرطة المائلة اللاحقة ('/') يجب أن تتطابق جميعها.

response_type مطلوب

يجب أن تضبط تطبيقات JavaScript قيمة المَعلمة على token. توجّه هذه القيمة خادم التفويض في Google إلى عرض رمز الدخول كزوج name=value في معرّف الجزء من معرّف الموارد المنتظم (#) الذي تتم إعادة توجيه المستخدم إليه بعد إكمال عملية التفويض.

scope مطلوب

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

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

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

state مقترَح

تحدّد أي قيمة سلسلة يستخدمها تطبيقك للحفاظ على الحالة بين طلب التفويض واستجابة خادم التفويض. يعرض الخادم القيمة الدقيقة التي ترسلها كزوج name=value في جزء من عنوان URL (#) لـ redirect_uri بعد موافقة المستخدم على طلب وصول تطبيقك أو رفضه.

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

include_granted_scopes اختياريّ

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

login_hint اختياريّ

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

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

prompt اختياريّ

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

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

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

نموذج إعادة التوجيه إلى خادم التفويض في 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&
 include_granted_scopes=true&
 response_type=token&
 state=state_parameter_passthrough_value&
 redirect_uri=https%3A//developers.google.com/oauthplayground&
 client_id=client_id

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

نموذج رمز JavaScript

يوضّح مقتطف JavaScript التالي كيفية بدء عملية التفويض في JavaScript بدون استخدام مكتبة برامج Google APIs للغة JavaScript. بما أنّ نقطة نهاية OAuth 2.0 هذه لا تتيح مشاركة الموارد مع نطاقات متعدّدة المصادر (CORS)، ينشئ المقتطف نموذجًا يفتح الطلب لنقطة النهاية هذه.

/*
 * Create form to request access token from Google's OAuth 2.0 server.
 */
function oauthSignIn() {
  // Google's OAuth 2.0 endpoint for requesting an access token
  var oauth2Endpoint = 'https://accounts.google.com/o/oauth2/v2/auth';

  // Create <form> element to submit parameters to OAuth 2.0 endpoint.
  var form = document.createElement('form');
  form.setAttribute('method', 'GET'); // Send as a GET request.
  form.setAttribute('action', oauth2Endpoint);

  // Parameters to pass to OAuth 2.0 endpoint.
  var params = {'client_id': 'YOUR_CLIENT_ID',
                'redirect_uri': 'YOUR_REDIRECT_URI',
                'response_type': 'token',
                'scope': 'https://www.googleapis.com/auth/drive.metadata.readonly https://www.googleapis.com/auth/calendar.readonly',
                'include_granted_scopes': 'true',
                'state': 'pass-through value'};

  // Add form parameters as hidden input values.
  for (var p in params) {
    var input = document.createElement('input');
    input.setAttribute('type', 'hidden');
    input.setAttribute('name', p);
    input.setAttribute('value', params[p]);
    form.appendChild(input);
  }

  // Add form to page and submit it to open the OAuth 2.0 endpoint.
  document.body.appendChild(form);
  form.submit();
}

الخطوة 2: تطلب 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.

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

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

org_internal

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

invalid_client

المصدر الذي تم إرسال الطلب منه غير مصرَّح به لهذا العميل. يمكنك الاطّلاع على origin_mismatch.

deleted_client

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

invalid_grant

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

origin_mismatch

قد لا يتطابق المخطط و/أو النطاق و/أو المنفذ الخاص بـ JavaScript الذي ينشئ طلب التفويض مع معرّف الموارد المنتظم (URI) لمصدر JavaScript المصرّح به والمسجّل لمعرّف عميل OAuth. راجِع مصادر JavaScript المصرَّح بها في صفحة "العملاء" ضمن Google Cloud Console.

redirect_uri_mismatch

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

قد لا يتطابق المخطط و/أو النطاق و/أو المنفذ الخاص بـ JavaScript الذي ينشئ طلب التفويض مع معرّف الموارد المنتظم (URI) لمصدر JavaScript المصرّح به والمسجّل لمعرّف عميل OAuth. راجِع صفحات JavaScript الأصلية المعتمدة في صفحة "العملاء" في Google Cloud Console.

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

invalid_request

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

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

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

نقاط نهاية OAuth 2.0

يُرسل خادم OAuth 2.0 ردًا إلى redirect_uri المحدّد في طلب رمز الدخول.

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

  • ردّ رمز الدخول:

    https://oauth2.example.com/callback#access_token=4/P7q7W91&token_type=Bearer&expires_in=3600

    بالإضافة إلى المَعلمة access_token، تحتوي سلسلة الجزء أيضًا على المَعلمة token_type التي يتم ضبطها دائمًا على Bearer، والمَعلمة expires_in التي تحدّد مدة صلاحية الرمز المميّز بالثواني. إذا تم تحديد المَعلمة state في طلب رمز الوصول، سيتم أيضًا تضمين قيمتها في الردّ.

  • ردّ خطأ:
    https://oauth2.example.com/callback#error=access_denied

نموذج استجابة خادم 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&
 include_granted_scopes=true&
 response_type=token&
 state=state_parameter_passthrough_value&
 redirect_uri=https%3A//developers.google.com/oauthplayground&
 client_id=client_id

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

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

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

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

لمزيد من المعلومات التفصيلية، يُرجى الاطّلاع على كيفية التعامل مع الأذونات الدقيقة.

نقاط نهاية OAuth 2.0

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

على سبيل المثال، يشير نموذج استجابة رمز الدخول التالي إلى أنّ المستخدم قد منح تطبيقك إذن الوصول إلى نشاط Drive للقراءة فقط وأذونات أحداث "تقويم Google":

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

نقاط نهاية OAuth 2.0

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

نموذج رمز JavaScript

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

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

var xhr = new XMLHttpRequest();
xhr.open('GET',
    'https://www.googleapis.com/drive/v3/about?fields=user&' +
    'access_token=' + params['access_token']);
xhr.onreadystatechange = function (e) {
  console.log(xhr.response);
};
xhr.send(null);

مثال مُكتمل

نقاط نهاية OAuth 2.0

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

بالنسبة إلى مسار OAuth 2.0، تتّبع الصفحة الخطوات التالية:

  1. ويوجّه المستخدم إلى خادم OAuth 2.0 من Google الذي يطلب الوصول إلى نطاقَي https://www.googleapis.com/auth/drive.metadata.readonly وhttps://www.googleapis.com/auth/calendar.readonly.
  2. بعد منح (أو رفض) إذن الوصول إلى نطاق واحد أو أكثر من النطاقات المطلوبة، تتم إعادة توجيه المستخدم إلى الصفحة الأصلية التي تحلّل رمز الدخول من سلسلة معرّف الجزء.
  3. تتحقّق الصفحة من النطاقات التي منح المستخدم التطبيق إذن الوصول إليها.
  4. إذا منح المستخدم إذن الوصول إلى النطاقات المطلوبة، تستخدم الصفحة رمز الدخول لإرسال نموذج طلب بيانات من واجهة برمجة التطبيقات.

    يستدعي طلب البيانات من واجهة برمجة التطبيقات طريقة about.get في Drive API لاسترداد معلومات عن حساب المستخدم المصرَّح له على Google Drive.

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

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

لتشغيل هذا الرمز محليًا، عليك ضبط قيم للمتغيّرَين YOUR_CLIENT_ID وYOUR_REDIRECT_URI بما يتوافق مع بيانات اعتماد التفويض. يجب ضبط المتغيّر YOUR_REDIRECT_URI على عنوان URL نفسه الذي يتم عرض الصفحة عليه. يجب أن تتطابق القيمة تمامًا مع أحد عناوين URI المصرّح بها لإعادة التوجيه لعميل OAuth 2.0، والتي تم ضبطها في صفحة "العملاء" في Cloud Console. إذا لم تتطابق هذه القيمة مع معرّف موارد منتظم (URI) معتمَد، سيظهر لك الخطأ redirect_uri_mismatch. يجب أيضًا أن يكون مشروعك قد فعّل واجهة برمجة التطبيقات المناسبة لهذا الطلب.

<html><head></head><body>
<script>
  var YOUR_CLIENT_ID = 'REPLACE_THIS_VALUE';
  var YOUR_REDIRECT_URI = 'REPLACE_THIS_VALUE';

  // Parse query string to see if page request is coming from OAuth 2.0 server.
  var fragmentString = location.hash.substring(1);
  var params = {};
  var regex = /([^&=]+)=([^&]*)/g, m;
  while (m = regex.exec(fragmentString)) {
    params[decodeURIComponent(m[1])] = decodeURIComponent(m[2]);
  }
  if (Object.keys(params).length > 0 && params['state']) {
    if (params['state'] == localStorage.getItem('state')) {
      localStorage.setItem('oauth2-test-params', JSON.stringify(params) );

      trySampleRequest();
    } else {
      console.log('State mismatch. Possible CSRF attack');
    }
  }

  // Function to generate a random state value
  function generateCryptoRandomState() {
    const randomValues = new Uint32Array(2);
    window.crypto.getRandomValues(randomValues);

    // Encode as UTF-8
    const utf8Encoder = new TextEncoder();
    const utf8Array = utf8Encoder.encode(
      String.fromCharCode.apply(null, randomValues)
    );

    // Base64 encode the UTF-8 data
    return btoa(String.fromCharCode.apply(null, utf8Array))
      .replace(/\+/g, '-')
      .replace(/\//g, '_')
      .replace(/=+$/, '');
  }

  // If there's an access token, try an API request.
  // Otherwise, start OAuth 2.0 flow.
  function trySampleRequest() {
    var params = JSON.parse(localStorage.getItem('oauth2-test-params'));
    if (params && params['access_token']) { 
      // User authorized the request. Now, check which scopes were granted.
      if (params['scope'].includes('https://www.googleapis.com/auth/drive.metadata.readonly')) {
        // User authorized read-only Drive activity permission.
        // Calling the APIs, etc.
        var xhr = new XMLHttpRequest();
        xhr.open('GET',
          'https://www.googleapis.com/drive/v3/about?fields=user&' +
          'access_token=' + params['access_token']);
        xhr.onreadystatechange = function (e) {
          if (xhr.readyState === 4 && xhr.status === 200) {
            console.log(xhr.response);
          } else if (xhr.readyState === 4 && xhr.status === 401) {
            // Token invalid, so prompt for user permission.
            oauth2SignIn();
          }
        };
        xhr.send(null);
      }
      else {
        // User didn't authorize read-only Drive activity permission.
        // Update UX and application accordingly
        console.log('User did not authorize read-only Drive activity permission.');
      }

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

  /*
   * Create form to request access token from Google's OAuth 2.0 server.
   */
  function oauth2SignIn() {
    // create random state value and store in local storage
    var state = generateCryptoRandomState();
    localStorage.setItem('state', state);

    // Google's OAuth 2.0 endpoint for requesting an access token
    var oauth2Endpoint = 'https://accounts.google.com/o/oauth2/v2/auth';

    // Create element to open OAuth 2.0 endpoint in new window.
    var form = document.createElement('form');
    form.setAttribute('method', 'GET'); // Send as a GET request.
    form.setAttribute('action', oauth2Endpoint);

    // Parameters to pass to OAuth 2.0 endpoint.
    var params = {'client_id': YOUR_CLIENT_ID,
                  'redirect_uri': YOUR_REDIRECT_URI,
                  'scope': 'https://www.googleapis.com/auth/drive.metadata.readonly https://www.googleapis.com/auth/calendar.readonly',
                  'state': state,
                  'include_granted_scopes': 'true',
                  'response_type': 'token'};

    // Add form parameters as hidden input values.
    for (var p in params) {
      var input = document.createElement('input');
      input.setAttribute('type', 'hidden');
      input.setAttribute('name', p);
      input.setAttribute('value', params[p]);
      form.appendChild(input);
    }

    // Add form to page and submit it to open the OAuth 2.0 endpoint.
    document.body.appendChild(form);
    form.submit();
  }
</script>

<button onclick="trySampleRequest();">Try sample request</button>
</body></html>

قواعد التحقّق من مصدر JavaScript

تطبّق Google قواعد التحقّق التالية على مصادر JavaScript لمساعدة المطوّرين في الحفاظ على أمان تطبيقاتهم. يجب أن تلتزم مصادر JavaScript بهذه القواعد. يُرجى الاطّلاع على القسم 3 من RFC 3986 لمعرفة تعريف النطاق والمضيف والمخطط المستخدَم في هذه القواعد.

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

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

المضيف

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

النطاق
  • يجب أن تنتمي نطاقات المستوى الأعلى (TLD) للمضيف إلى قائمة اللاحقات العلنية.
  • لا يمكن أن تكون نطاقات المضيف “googleusercontent.com”.
  • لا يمكن أن تحتوي مصادر JavaScript على نطاقات لتقصير عناوين URL (مثل goo.gl) ما لم يكن التطبيق يملك النطاق.
  • Userinfo

    لا يمكن أن تحتوي مصادر JavaScript على المكوّن الفرعي userinfo.

    Path

    لا يمكن أن تحتوي مصادر JavaScript على مكوّن المسار.

    طلب بحث

    لا يمكن أن تحتوي مصادر JavaScript على مكوّن طلب البحث.

    Fragment

    لا يمكن أن تحتوي مصادر JavaScript على مكوّن التجزئة.

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

    التفويض المتزايد

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

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

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

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

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

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

    نقاط نهاية OAuth 2.0

    لإضافة نطاقات إلى رمز الدخول حالي، يجب تضمين المَعلمة include_granted_scopes في طلبك إلى خادم OAuth 2.0 من Google.

    يوضّح مقتطف الرمز التالي كيفية إجراء ذلك. يفترض المقتطف أنّك خزّنت النطاقات التي يكون رمز الدخول صالحًا لها في مساحة التخزين المحلية للمتصفّح. (يخزّن رمز المثال المكتمل قائمة بالنطاقات التي يكون رمز الوصول صالحًا لها من خلال ضبط السمة oauth2-test-params.scope في مساحة التخزين المحلية للمتصفّح).

    يقارن المقتطف النطاقات التي يكون رمز الدخول صالحًا لها بالنطاق الذي تريد استخدامه لطلب بحث معيّن. إذا لم يغطِّ رمز الدخول هذا النطاق، سيبدأ مسار OAuth 2.0. في هذه الحالة، تكون دالة oauth2SignIn هي نفسها التي تم تقديمها في الخطوة 2 (والتي يتم تقديمها لاحقًا في المثال الكامل).

    var SCOPE = 'https://www.googleapis.com/auth/drive.metadata.readonly';
    var params = JSON.parse(localStorage.getItem('oauth2-test-params'));
    
    var current_scope_granted = false;
    if (params.hasOwnProperty('scope')) {
      var scopes = params['scope'].split(' ');
      for (var s = 0; s < scopes.length; s++) {
        if (SCOPE == scopes[s]) {
          current_scope_granted = true;
        }
      }
    }
    
    if (!current_scope_granted) {
      oauth2SignIn(); // This function is defined elsewhere in this document.
    } else {
      // Since you already have access, you can proceed with the API request.
    }

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

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

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

    نقاط نهاية OAuth 2.0

    لإبطال رمز مميّز آليًا، يرسل تطبيقك طلبًا إلى 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 مع رمز خطأ.

    يوضّح مقتطف JavaScript التالي كيفية إبطال رمز مميّز في JavaScript بدون استخدام مكتبة برامج Google APIs للغة JavaScript. بما أنّ نقطة نهاية OAuth 2.0 من Google لإبطال الرموز المميّزة لا تتيح مشاركة الموارد المتعدّدة المصادر (CORS)، ينشئ الرمز نموذجًا ويرسله إلى نقطة النهاية بدلاً من استخدام طريقة XMLHttpRequest() لنشر الطلب.

    function revokeAccess(accessToken) {
      // Google's OAuth 2.0 endpoint for revoking access tokens.
      var revokeTokenEndpoint = 'https://oauth2.googleapis.com/revoke';
    
      // Create <form> element to use to POST data to the OAuth 2.0 endpoint.
      var form = document.createElement('form');
      form.setAttribute('method', 'post');
      form.setAttribute('action', revokeTokenEndpoint);
    
      // Add access token to the form so it is set as value of 'token' parameter.
      // This corresponds to the sample curl request, where the URL is:
      //      https://oauth2.googleapis.com/revoke?token={token}
      var tokenField = document.createElement('input');
      tokenField.setAttribute('type', 'hidden');
      tokenField.setAttribute('name', 'token');
      tokenField.setAttribute('value', accessToken);
      form.appendChild(tokenField);
    
      // Add form to page and submit it to actually revoke the token.
      document.body.appendChild(form);
      form.submit();
    }

    تنفيذ ميزة "الحماية العابرة للحساب"

    من الخطوات الإضافية التي يجب اتّخاذها لحماية حسابات المستخدمين تنفيذ ميزة "الحماية العابرة للحساب" من خلال الاستفادة من خدمة "الحماية العابرة للحساب" من 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

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