انتقل إلى المحتوى الرئيسي

OAuth

يقبل خادم MCP نوعين من بيانات الاعتماد.

مفتاح APIOAuth 2.1
من ينشئهالتاجر، من لوحة التحكمالعميل، تلقائيًا
ما يفعله التاجرينسخ المفتاح إلى العميليضغط موافقة في صفحة الموافقة
من يحمل السركل من ألصقتَ المفتاح عندهلا أحد — يحمل العميل رمزًا دوّارًا
الإلغاءاحذف المفتاحالإعدادات ← MCP ← فصل
الأنسب لـالوكلاء الذين تبنيهم، وأدوات الطرفية، والسكربتات، وخطوط CIالمساعدين الجاهزين: ChatGPT وClaude وكل ما فيه زر «اربط تطبيقًا»

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

ما الذي يدعمه الخادم

نوع المنحAuthorization code لعميل عام (token_endpoint_auth_method: none)
PKCEإلزامي، بطريقة S256 حصرًا — وplain مرفوضة
تسجيل العملاءديناميكي (RFC 7591) — يسجّل العملاء أنفسهم بلا إعداد يدوي
الاكتشافبيانات المورد المحمي (RFC 9728) وبيانات خادم التفويض (RFC 8414)
رموز التجديددوّارة عند كل استخدام، مع كشف إعادة الاستخدام
الإلغاءRFC 7009، إضافةً إلى فصل الاتصال من لوحة تحكم التاجر
النطاقاتmcp:read وmcp:write
الوسيط resourceمقبول ومتجاهَل (RFC 8707) — فجمهور هذا الخادم ثابت

العميل الذي يتقن تفويض MCP لا يحتاج أيًّا من العناوين أدناه: فهو يقرأ ترويسة WWW-Authenticate في استجابة 401 من /mcp ثم يكتشف الباقي بنفسه.

العناوين

الغرضالطريقة والمسار
بيانات المورد المحميGET https://api.taketheme.com/.well-known/oauth-protected-resource
بيانات خادم التفويضGET https://api.taketheme.com/.well-known/oauth-authorization-server
تسجيل العميلPOST https://api.taketheme.com/api/v1/oauth/register
التفويض (صفحة متصفح)GET https://dashboard.taketheme.com/oauth/authorize
الرموزPOST https://api.taketheme.com/api/v1/oauth/token
الإلغاءPOST https://api.taketheme.com/api/v1/oauth/revoke

وتُقدَّم وثيقة المورد المحمي أيضًا على /.well-known/oauth-protected-resource/mcp، من أجل العملاء الذين يضعون مسار المورد بعد مقطع well-known.

المسار

  1. يرسل العميل POST إلى /mcp بلا بيانات اعتماد فيتلقى 401 مع:

    WWW-Authenticate: Bearer resource_metadata="https://api.taketheme.com/.well-known/oauth-protected-resource"
  2. يجلب تلك الوثيقة، ويتبع authorization_servers إلى بيانات خادم التفويض، ثم يسجّل نفسه على registration_endpoint. ويُرجع التسجيل client_id بلا أي سر للعميل.

  3. يفتح authorization_endpoint في متصفح التاجر ومعه client_id وredirect_uri وcode_challenge وcode_challenge_method=S256 وscope وstate.

  4. يصل التاجر إلى صفحة الموافقة. وإن لم يكن مسجّل الدخول سجّل أولًا ثم عاد إليها. تعرض الصفحة اسم العميل والمتجر والنطاقات المطلوبة، ولا تفعل شيئًا حتى يختار. والرفض يُرجع error=access_denied إلى العميل.

  5. عند الموافقة يعود المتصفح إلى redirect_uri الخاص بالعميل ومعه code صالح لاستخدام واحد وعمره عشر دقائق.

  6. يبادل العميل الرمز على عنوان الرموز مع code_verifier، فيتلقى رمز وصول ورمز تجديد.

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

النطاقات

يوجد نطاقان فقط، وطلب أي شيء غيرهما يُفشل طلب التفويض.

النطاقما يمنحه
mcp:readREAD على PRODUCTS وORDERS وCATEGORIES وCUSTOMERS وSTORE_SETTINGS وTHEME وBLOGS وANALYTICS
mcp:writeما سبق إضافةً إلى WRITE وUPDATE وDELETE على الموارد نفسها

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

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

get_review_summary غير متاحة عبر OAuth

تحتاج هذه الأداة صلاحية REVIEWS، ولا يمنحها mcp:read ولا mcp:write. فاستدعاؤها على اتصال OAuth يُرجع permission_denied. استخدم مفتاح API لبيانات التقييمات ريثما يُصحَّح ذلك.

الرموز

رمز الوصول — رمز JWT صالح ساعة واحدة، جمهوره /mcp. يُقبل على عنوان MCP دون سواه: وتقديمه لأي مسار REST يُرجع 403، فالرمز المسرَّب لا يمكن نقله إلى بقية الـ API.

رمز التجديد — رمز مبهم يبدأ بـ tt_rt_، ويدور عند كل استخدام. وتقديم رمز سبق أن دار يُعامَل كسرقة: يُلغى عندها كامل عائلة الرموز فورًا ويضطر العميل إلى إعادة التفويض. فاحتفظ بأحدث رمز تسلّمته فقط.

وتحمل الرموز المتجر الذي كان نشطًا لدى التاجر لحظة الموافقة. وكما هو الحال مع مفاتيح API، فـstoreId ليس وسيطًا لأي أداة — فلا يستطيع أي توجيه نصي أن يوجّه اتصالًا نحو بيانات تاجر آخر.

إلغاء الوصول

يستطيع التاجر فصل أي عميل من الإعدادات ← MCP، وهو ما يقتل عائلة الرموز كاملة دفعة واحدة.

وعلى العملاء الإلغاء عند تسجيل الخروج (RFC 7009):

curl -X POST https://api.taketheme.com/api/v1/oauth/revoke \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "token=tt_rt_YOUR_REFRESH_TOKEN" \
-d "token_type_hint=refresh_token" \
-d "client_id=YOUR_CLIENT_ID"

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

حدود المعدل

عناوين OAuth محدودة بحسب عنوان IP، بمعزل عن حدود الـ API:

العنوانالحد
/oauth/register5 في الساعة
/oauth/authorize10 في الدقيقة
/oauth/token30 في الدقيقة
/oauth/revoke20 في الدقيقة

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

تنفيذه يدويًا

مفيد لاختبار عميل، أو لتطبيق أصيل يريد المسار دون مكتبة.

التسجيل:

curl -X POST https://api.taketheme.com/api/v1/oauth/register \
-H "Content-Type: application/json" \
-d '{
"client_name": "My Agent",
"redirect_uris": ["http://127.0.0.1:8976/callback"],
"grant_types": ["authorization_code", "refresh_token"],
"response_types": ["code"],
"token_endpoint_auth_method": "none"
}'

يجب أن تكون عناوين إعادة التوجيه بروتوكول https:، أو مخططًا مخصصًا (myapp://callback)، أو http: على الحلقة المحلية (localhost أو 127.0.0.1 أو [::1]). وبحد أقصى عشرة عناوين لكل عميل.

توليد زوج PKCE وإرسال التاجر إلى صفحة الموافقة:

VERIFIER=$(openssl rand -base64 60 | tr -d '\n=+/' | cut -c1-64)
CHALLENGE=$(printf '%s' "$VERIFIER" | openssl dgst -sha256 -binary | openssl base64 | tr '+/' '-_' | tr -d '=')

echo "https://dashboard.taketheme.com/oauth/authorize?client_id=$CLIENT_ID\
&redirect_uri=http://127.0.0.1:8976/callback\
&code_challenge=$CHALLENGE&code_challenge_method=S256\
&scope=mcp:read%20mcp:write&state=$(openssl rand -hex 16)"

مبادلة الرمز:

curl -X POST https://api.taketheme.com/api/v1/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code" \
-d "client_id=$CLIENT_ID" \
-d "code=$CODE" \
-d "redirect_uri=http://127.0.0.1:8976/callback" \
-d "code_verifier=$VERIFIER"
{
"access_token": "eyJhbGciOi...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "tt_rt_...",
"scope": "mcp:read mcp:write"
}

ثم استدعِ عنوان MCP بترويسة Authorization: Bearer <access_token> تمامًا كما تفعل مع مفتاح API.

التجديد:

curl -X POST https://api.taketheme.com/api/v1/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=refresh_token" \
-d "client_id=$CLIENT_ID" \
-d "refresh_token=$REFRESH_TOKEN"

الأخطاء

الرمزالمعنى
UNAUTHORIZED_CLIENTclient_id غير مسجَّل أصلًا
INVALID_GRANTالرمز أُعيد استخدامه أو انتهى أو صدر لعميل آخر؛ أو redirect_uri غير مطابق؛ أو فشل تحقق PKCE؛ أو رمز التجديد غير صالح أو أُعيد استخدامه
INVALID_REQUESTcode_challenge مفقود، أو code_challenge_method ليس S256
INVALID_SCOPEطُلب نطاق غير mcp:read / mcp:write
STORE_REQUIREDالتاجر الموافِق ليس لديه متجر نشط محدد
INVALID_AUDIENCEقُدِّم رمز OAuth في مكان غير /mcp
TOKEN_REVOKEDأُلغي الرمز قبل انتهائه
JWT_EXPIREDتجاوز رمز الوصول ساعته — جدّده

التالي