المصادقة
رموز API للتكاملات، وجلسات JWT للتطبيقات الموجَّهة للمستخدمين، ونموذج الصلاحيات الذي يُقيَّم عليه كلاهما.
آخر مراجعة: 2026-08-23
نوعان من الاعتمادات
يُقدَّم كلاهما بالطريقة نفسها - Authorization: Bearer <value> - ويميّزهما الخادم من القيمة نفسها. وأيّهما تحتاج يتوقّف على من الذي يتصرّف.
| رمز API | جلسة JWT | |
|---|---|---|
| الشكل | ct_live_… | JWT (eyJ…) |
| ينوب عن | تكامل | شخص مسجَّل الدخول |
| مصدره | الإعدادات ← رموز API أو POST /api-tokens | POST /auth/login |
| العمر | حتى الإبطال أو تاريخ الانتهاء | نحو ساعة، ثم يُجدَّد |
| الأنسب لـ | خادم إلى خادم، cron، ETL | تطبيق يسجّل مستخدموك الدخول إليه |
رموز API (المستحسَنة للتكاملات)
رمز الـ API يخصّ مساحة العمل لا شخصًا بعينه، فيبقى التكامل عاملًا حين يغادر الزميل الذي أعدّه. أنشئه من التطبيق عبر الإعدادات ← رموز API، أو عبر الـ API:
curl -sS -X POST https://your-host/api/v1/api-tokens \
-H "Authorization: Bearer <your session token>" \
-H "Content-Type: application/json" \
-d '{
"name": "Storefront sync",
"description": "Pushes orders from the website",
"permissions": ["crm.contacts.read", "crm.contacts.write", "sales.orders.write"],
"expires_at": "2027-01-01T00:00:00"
}'{
"id": 12,
"name": "Storefront sync",
"token": "ct_live_9Xf2…",
"token_prefix": "ct_live_9Xf2",
"permissions": ["crm.contacts.read", "crm.contacts.write", "sales.orders.write"],
"expires_at": "2027-01-01T00:00:00",
"created_at": "2026-08-23T10:12:00"
}حقلان يحدّدان مدى ما يستطيعه الرمز، وهما مستقلان:
- `permissions` - ما يُسمح له بفعله. امنح أضيق مجموعة يحتاجها التكامل فعلًا.
GET /permissionsيسرد كل رمز يعرّفه المنتج. - `acts_as_user_id` - ممّن يستعير *رؤية السجلات*. احذفه ليرث مقعد المستخدم المُنشئ، وهو الافتراض الآمن؛ أرسل
nullلرمز بلا تقييد. لا يضيف صلاحيات أبدًا - يضيّق فقط نطاق السجلات التي تبلغها الصلاحيات الممنوحة.
الإبطال عبر POST /api-tokens/{token_id}/revoke، ويتوقف الرمز فورًا. وGET /api-tokens/{token_id}/audit يبيّن ما فعله، وهو أول ما يُراجَع عند الاشتباه بتسريب.
رموز الجلسة
استخدمها حين يسجّل تطبيقك دخول *شخص* ويتصرّف نيابة عنه، فيُنسب كل إجراء إليه ويُقيَّم بدوره هو.
curl -sS -X POST https://your-host/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{
"tenant_slug": "acme",
"email": "sara@example.com",
"password": "…"
}'{
"access_token": "eyJhbGciOi…",
"refresh_token": "eyJhbGciOi…",
"token_type": "bearer",
"user": { "id": 5, "email": "sara@example.com", "first_name": "Sara", "last_name": "Ahmadi" },
"tenant": { "id": 17, "slug": "acme", "name": "Acme Inc." },
"permissions": ["crm.contacts.read", "crm.contacts.write", "…"]
}tenant_slug مطلوب: قد يوجد البريد نفسه في أكثر من مساحة عمل، والمُعرِّف اللفظي هو ما يحدّد أيّها تدخل.
رمز الوصول قصير العمر. حين يعيد نداء 401، بادِل رمز التجديد على POST /auth/refresh - أي أرسل رمز التجديد بوصفه bearer - ثم أعد المحاولة مرة واحدة. مسار التجديد يقبل رموز التجديد فقط؛ ورمز الـ API لا يُجدَّد ولا يحتاج ذلك.
curl -sS -X POST https://your-host/api/v1/auth/refresh \
-H "Authorization: Bearer <refresh_token>"الصلاحيات
الصلاحيات رموز منقوطة بصيغة module.resource.action، وكل نقطة طرفية محميّة تسمّي الرمز الذي تتطلّبه بالضبط. لا توجد نطاقات (scopes) منفصلة عن الصلاحيات: رمز الـ API يحمل مجموعة فرعية من الرموز نفسها التي يحملها الدور.
crm.contacts.read crm.contacts.write crm.contacts.delete
crm.contacts.view_phone crm.deals.read crm.tasks.write
webhooks.read webhooks.write api_tokens.write
events.read finance.invoices.read sales.orders.writeالصلاحية الناقصة تعطي 403 يسمّي details.required فيها ما كان مطلوبًا - فيسجّل العميل شيئًا قابلًا للتصرّف بدل «ممنوع» فحسب.
{
"error": "forbidden",
"message": "Missing required permissions",
"details": { "required": ["crm.contacts.write"] }
}الحفاظ على الرمز
- احفظه في مدير أسرار أو متغيّر بيئة - لا في المستودع ولا في صورة الحاوية ولا في حزمة الواجهة الأمامية.
- امنح أضيق مجموعة صلاحيات تكفي، ورمزًا منفصلًا لكل تكامل، حتى لا يُسقِط إبطالُ واحدٍ البقيةَ.
- اضبط
expires_atحين يكون للتكامل عمر معروف. - دوِّر الرموز بجدول: أنشئ البديل، ثم انشره، ثم أبطِل القديم - بهذا الترتيب حتى لا تقع فجوة.
- أبطِل فورًا عند الاشتباه، واقرأ
GET /api-tokens/{token_id}/auditبعد ذلك لا قبله.