# الويب هوك (Webhooks) و HMAC تعرف على كيفية استقبال إشعارات لحظية آمنة عند التحقق من رقم هاتف. --- الـ **Webhooks** هي الطريقة الأسرع والأكثر أماناً لمعرفة أن المستخدم قام بالتحقق بنجاح دون الحاجة لعمل SSE (Server-Sent Events) (فحص مستمر). عندما يرسل المستخدم الرسالة وتتم مطابقتها بنجاح، يقوم نظامنا بإرسال طلب **POST** إلى رابط (URL) تقوم أنت بتحديده مسبقاً في إعدادات المشروع. ### أمان الويب هوك (HMAC Signature) لضمان أن الطلبات قادمة حقاً من خوادمنا وليست هجمات وهمية، نقوم بتوقيع كل طلب باستخدام خوارزمية **HMAC-SHA256**. 1. اذهب لإعدادات المشروع وقم بتوليد **Webhook Secret**. 2. سيتم إرفاق توقيع مشفر في ترويسة الطلب (Header) باسم `x-webhook-signature`. 3. يجب عليك في خادمك حساب التوقيع باستخدام نفس الـ Secret الخاص بك ومقارنته بالتوقيع المرسل. ## Code Examples ### Node.js (Express) ```javascript const express = require('express'); const crypto = require('crypto'); const app = express(); const WEBHOOK_SECRET = 'your_webhook_secret_here'; // Must parse raw body to verify signature correctly app.use(express.json()); app.post('/webhook/reotp', (req, res) => { const signatureHeader = req.headers['x-webhook-signature']; const payloadString = JSON.stringify(req.body); // Calculate HMAC SHA256 const expectedSignature = crypto .createHmac('sha256', WEBHOOK_SECRET) .update(payloadString) .digest('hex'); // Securely compare signatures if (signatureHeader !== expectedSignature) { return res.status(401).send('Invalid signature'); } // Handle successful verification const { event, phoneNumber, requestId } = req.body; if (event === 'verification.success') { console.log(`User ${phoneNumber} verified! (ID: ${requestId})`); // Login user, create session, update DB, etc. } // Must return 200 OK so we know it was delivered res.status(200).send('OK'); }); app.listen(3000, () => console.log('Listening for Webhooks...')); ``` ### Next.js (App Router) ```javascript import { NextResponse } from 'next/server'; import crypto from 'crypto'; const WEBHOOK_SECRET = process.env.REOTP_WEBHOOK_SECRET; export async function POST(request: Request) { const signatureHeader = request.headers.get('x-webhook-signature'); const payloadText = await request.text(); // Raw payload string if (!WEBHOOK_SECRET || !signatureHeader) { return NextResponse.json({ error: "Missing secret or signature" }, { status: 400 }); } // Calculate HMAC SHA256 const expectedSignature = crypto .createHmac('sha256', WEBHOOK_SECRET) .update(payloadText) .digest('hex'); if (signatureHeader !== expectedSignature) { return NextResponse.json({ error: "Invalid signature" }, { status: 401 }); } // Handle successful verification const data = JSON.parse(payloadText); if (data.event === 'verification.success') { console.log(`User ${data.phoneNumber} verified! (ID: ${data.requestId})`); // Login user, create session, update DB, etc. } // Return 200 OK return NextResponse.json({ success: true }, { status: 200 }); } ```