موصل Auth0
اربط Auth0 بـ Brevo عبر Tajo لمزامنة ملفات المستخدمين المُصادق عليهم كجهات اتصال تسويقية، وتشغيل الأتمتة بناءً على أحداث المصادقة، وإثراء بيانات عملائك برؤى إدارة الهوية والوصول.
نظرة عامة
| الخاصية | القيمة |
|---|---|
| المنصة | Auth0 (by Okta) |
| الفئة | الهوية والوصول (مخصص) |
| تعقيد الإعداد | متوسط |
| تكامل رسمي | لا |
| البيانات المتزامنة | المستخدمون، الأحداث، الأدوار، الهويات |
| طريقة المصادقة | Machine-to-Machine OAuth 2.0 |
الميزات
- مزامنة ملف المستخدم - زامن ملفات مستخدم Auth0 إلى جهات اتصال Brevo
- أحداث المصادقة - شغّل الأتمتة عند تسجيل الدخول، والتسجيل، وإعادة تعيين كلمة المرور
- تقسيم قائم على الأدوار - قسّم جهات الاتصال بناءً على أدوار وأذونات Auth0
- بيانات الهوية الاجتماعية - أثرِ جهات الاتصال بمعلومات ملف تسجيل الدخول الاجتماعي
- تتبع نشاط تسجيل الدخول - تتبع آخر تسجيل دخول، وعدد التسجيلات، وبيانات الجهاز
- دعم متعدد المستأجرين - زامن المستخدمين عبر مستأجري Auth0 متعددين
المتطلبات المسبقة
قبل أن تبدأ، تأكد من توفر ما يلي:
- حساب Auth0 مع وصول API
- تطبيق Machine-to-Machine مسجل في Auth0
- أذونات Management API ممنوحة لتطبيق M2M
- حساب Brevo مع وصول API
- حساب Tajo مع أذونات الموصلات
المصادقة
Machine-to-Machine OAuth 2.0
# Create an M2M application in Auth0 Dashboardexport AUTH0_DOMAIN=your-tenant.auth0.comexport AUTH0_CLIENT_ID=your_client_idexport AUTH0_CLIENT_SECRET=your_client_secretexport AUTH0_AUDIENCE=https://your-tenant.auth0.com/api/v2/// Get Management API access tokenconst tokenResponse = await fetch( `https://${process.env.AUTH0_DOMAIN}/oauth/token`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ client_id: process.env.AUTH0_CLIENT_ID, client_secret: process.env.AUTH0_CLIENT_SECRET, audience: process.env.AUTH0_AUDIENCE, grant_type: 'client_credentials' }) });
const { access_token } = await tokenResponse.json();// Token is valid for 24 hours by defaultأذونات API
امنح فقط النطاقات المطلوبة لتطبيق M2M الخاص بك: read:users، و read:user_idp_tokens، و read:roles، و read:logs. تجنب منح أذونات الكتابة ما لم تكن ضرورية.
الإعداد
الإعداد الأساسي
connectors: auth0: enabled: true domain: "${AUTH0_DOMAIN}" client_id: "${AUTH0_CLIENT_ID}" client_secret: "${AUTH0_CLIENT_SECRET}" audience: "https://${AUTH0_DOMAIN}/api/v2/"
sync: users: true events: true roles: true schedule: "0 */4 * * *" # Every 4 hours
lists: all_users: 20 verified_users: 21 social_login: 22ربط الحقول
field_mapping: email: email given_name: FIRSTNAME family_name: LASTNAME nickname: NICKNAME picture: AVATAR_URL email_verified: EMAIL_VERIFIED logins_count: LOGIN_COUNT last_login: LAST_LOGIN_DATE created_at: SIGNUP_DATE user_metadata.phone: SMS user_metadata.company: COMPANY app_metadata.plan: SUBSCRIPTION_PLAN app_metadata.role: USER_ROLEنقاط نهاية API
| نقطة النهاية | الطريقة | الوصف |
|---|---|---|
https://{domain}/api/v2/users | GET | عرض أو البحث عن المستخدمين |
https://{domain}/api/v2/users/{id} | GET | الحصول على مستخدم |
https://{domain}/api/v2/users/{id} | PATCH | تحديث بيانات المستخدم |
https://{domain}/api/v2/users/{id}/roles | GET | الحصول على أدوار المستخدم |
https://{domain}/api/v2/roles | GET | عرض جميع الأدوار |
https://{domain}/api/v2/logs | GET | الحصول على أحداث السجل |
https://{domain}/api/v2/stats/active-users | GET | الحصول على عدد المستخدمين النشطين |
https://{domain}/api/v2/stats/daily | GET | الحصول على الإحصائيات اليومية |
https://{domain}/oauth/token | POST | الحصول على رمز الوصول |
أمثلة البرمجة
تهيئة الموصل
import { TajoClient } from '@tajo/sdk';
const tajo = new TajoClient({ apiKey: process.env.TAJO_API_KEY, brevoApiKey: process.env.BREVO_API_KEY});
await tajo.connectors.connect('auth0', { domain: process.env.AUTH0_DOMAIN, clientId: process.env.AUTH0_CLIENT_ID, clientSecret: process.env.AUTH0_CLIENT_SECRET});مزامنة المستخدمين إلى Brevo
// Paginate through Auth0 userslet page = 0;const perPage = 50;let hasMore = true;
while (hasMore) { const response = await fetch( `https://${domain}/api/v2/users?` + new URLSearchParams({ page: page.toString(), per_page: perPage.toString(), include_totals: 'true', search_engine: 'v3', q: 'email_verified:true' }), { headers: { 'Authorization': `Bearer ${accessToken}` } } );
const { users, total } = await response.json();
for (const user of users) { await tajo.contacts.sync({ email: user.email, attributes: { FIRSTNAME: user.given_name, LASTNAME: user.family_name, LOGIN_COUNT: user.logins_count, LAST_LOGIN_DATE: user.last_login, SIGNUP_DATE: user.created_at, EMAIL_VERIFIED: user.email_verified }, listIds: [20] }); }
page++; hasMore = (page * perPage) < total;}تتبع أحداث المصادقة عبر Log Streams
// Set up Auth0 Log Stream webhook// Configure in Auth0 Dashboard > Monitoring > Streams
app.post('/webhooks/auth0', async (req, res) => { // Verify authorization header const authHeader = req.headers.authorization; if (authHeader !== `Bearer ${process.env.AUTH0_WEBHOOK_TOKEN}`) { return res.status(401).send('Unauthorized'); }
const logs = req.body;
for (const log of logs) { switch (log.data.type) { case 's': // Successful login await tajo.events.track({ email: log.data.details.email, event: 'user_login', properties: { ip: log.data.ip, user_agent: log.data.user_agent, connection: log.data.connection } }); break; case 'ss': // Successful signup await tajo.contacts.sync({ email: log.data.details.email, attributes: { SIGNUP_DATE: log.data.date }, listIds: [20] }); break; case 'sp': // Successful password change await tajo.events.track({ email: log.data.details.email, event: 'password_changed' }); break; } }
res.status(200).send('OK');});التقسيم القائم على الأدوار
// Sync user roles for segmentationconst rolesResponse = await fetch( `https://${domain}/api/v2/users/${userId}/roles`, { headers: { 'Authorization': `Bearer ${accessToken}` } });
const roles = await rolesResponse.json();const roleNames = roles.map(r => r.name).join(', ');
await tajo.contacts.update(userEmail, { attributes: { USER_ROLE: roleNames, IS_ADMIN: roles.some(r => r.name === 'admin') }});حدود المعدل
| فئة نقطة النهاية | الحد | ملاحظات |
|---|---|---|
| Management API | 50 طلب/ثانية (Free) | لكل مستأجر |
| Management API | 100 طلب/ثانية (Paid) | لكل مستأجر |
| Authentication API | متفاوت | بناءً على الخطة |
| Log Streams | في الوقت الفعلي | لا يوجد حد معدل على التسليم |
| الترقيم | 50 عنصرًا/صفحة كحد أقصى | استخدم معلمات page و per_page |
الترقيم مطلوب
يُرجع Auth0 Management API ما أقصاه 50 نتيجة لكل صفحة. طبّق الترقيم دائمًا باستخدام معلمات page و per_page. أدرج include_totals=true للحصول على العدد الإجمالي.
استكشاف الأخطاء
| المشكلة | السبب | الحل |
|---|---|---|
| 401 Unauthorized | انتهت صلاحية الرمز | اطلب رمز M2M جديد (صلاحية 24 ساعة) |
| 403 Forbidden | نطاقات مفقودة | امنح الأذونات المطلوبة لتطبيق M2M |
| قائمة مستخدمين فارغة | خطأ في استعلام البحث | استخدم بنية استعلام Lucene لمحرك v3 |
| بيانات وصفية مفقودة | البيانات الوصفية غير مضبوطة | تحقق من user_metadata و app_metadata |
| حد معدل 429 | عدد كبير من الطلبات | نفّذ التراجع برؤوس إعادة المحاولة |
وضع التصحيح
connectors: auth0: debug: true log_level: verbose log_sync: trueأفضل الممارسات
- استخدم Log Streams - بث أحداث في الوقت الفعلي بدلاً من استطلاع Logs API
- طبّق الترقيم - رقّم دائمًا استعلامات قائمة المستخدمين للمستأجرين الكبار
- احفظ رموز M2M مؤقتًا - أعد استخدام الرموز حتى قرب انتهاء الصلاحية (عمر افتراضي 24 ساعة)
- استخدم محرك البحث v3 - استخدم بنية استعلام Lucene لبحث مستخدم فعال
- زامن المستخدمين المُوَثَّقين فقط - صفِّ على
email_verified:trueلتجنب جهات الاتصال غير المُوَثَّقة - استفد من البيانات الوصفية للمستخدم - خزّن السمات المخصصة في Auth0 user_metadata للمزامنة
الأمان
- Machine-to-Machine OAuth - منح client credentials لمصادقة خادم إلى خادم
- أذونات محددة النطاق - امنح الحد الأدنى من نطاقات Management API المطلوبة
- تدوير الرمز - تنتهي صلاحية رموز M2M بعد 24 ساعة افتراضيًا
- مصادقة Log Stream - استخدم التحقق من رمز bearer لنقاط نهاية webhook
- عزل المستأجر - تكوينات منفصلة لكل مستأجر Auth0
- النقل المشفر - TLS 1.2+ لجميع اتصالات API