قبل أن ترسل علاقات أي حدث إلى خادمك، عليها أن تتأكد أن الرابط يخصك فعلاً. هذا ما يفعله التوثيق: ترسل علاقات طلب تحقق إلى رابطك، وتجيب أنت بتوقيع لا يستطيع إنتاجه إلا من يملك المفتاح السري للخطاف.
يجب توثيق خطاف الويب قبل أن يمكن تفعيله، وتعود حالته إلى غير موثق في كل مرة تُغيّر فيها رابطه.
عند الضغط على توثيق في بطاقة الخطاف (أو استدعاء نقطة نهاية التوثيق)، ترسل علاقات طلب GET إلى رابطك مع مُعاملين في الرابط:
GET /your-endpoint?payload=Xk3aQ×tamp=1756600000 HTTP/1.1
Host: yourdomain.com
| المُعامل | الوصف |
|---|---|
payload |
نص عشوائي من 5 خانات، يختلف في كل مرة. |
timestamp |
الطابع الزمني (Unix) بالثواني للحظة إرسال طلب التحقق. |
أمام رابطك 10 ثوانٍ للإجابة. والرد الأبطأ من ذلك يُعامل تماماً كالرد الخاطئ، ويبقى الخطاف غير موثق.
اربط payload ثم timestamp بهذا الترتيب ودون أي فاصل بينهما، ووقّع الناتج بخوارزمية HMAC SHA-256 باستخدام المفتاح السري للخطاف، وأعد الناتج الست عشري بالأحرف الصغيرة كمحتوى الرد كاملاً:
signature = hmac_sha256(payload + timestamp, secret)
يجب أن يكون الرد:
2xx،تُقارن محتويات الرد بالتوقيع المتوقع حرفاً بحرف، لذا يكفي سطر جديد إضافي واحد ليفشل التحقق.
المفتاح السري هو المعروض في بطاقة الخطاف ضمن الإعدادات > التكاملات > خطافات الويب. اقرأه من إعدادات تطبيقك، ولا تكتبه مباشرة في مستودع عام.
$secret = getenv('ALAAQAT_WEBHOOK_SECRET');
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
$signature = hash_hmac('sha256', $_GET['payload'].$_GET['timestamp'], $secret);
header('Content-Type: text/plain');
echo $signature; // دون سطر جديد
exit;
}
Route::get('/alaaqat-webhook', function (Request $request) {
$signature = hash_hmac(
'sha256',
$request->query('payload').$request->query('timestamp'),
config('services.alaaqat.webhook_secret')
);
return response($signature)->header('Content-Type', 'text/plain');
});
const crypto = require('crypto');
app.get('/alaaqat-webhook', (req, res) => {
const signature = crypto
.createHmac('sha256', process.env.ALAAQAT_WEBHOOK_SECRET)
.update(req.query.payload + req.query.timestamp)
.digest('hex');
res.type('text/plain').send(signature);
});
import hashlib
import hmac
import os
@app.get('/alaaqat-webhook')
def validate():
message = request.args['payload'] + request.args['timestamp']
signature = hmac.new(
os.environ['ALAAQAT_WEBHOOK_SECRET'].encode(),
message.encode(),
hashlib.sha256,
).hexdigest()
return signature, 200, {'Content-Type': 'text/plain'}
الرابط نفسه يستقبل طلب التحقق وإرسالات الأحداث معاً، لذا فرّق بينهما حسب طريقة الطلب:
GET ← طلب تحقق؛ أجب بالتوقيع.POST ← إرسالة حدث؛ أجب بأي رمز ضمن 2xx.تتحول حالة الخطاف إلى مُوَثَّق ويصبح زر تفعيل متاحاً. فعّله لتبدأ الأحداث المشترك بها بالوصول.
ترد علاقات برمز 403 والرسالة:
{
"message": "Unable to validate the webhook. Please ensure that the secret key is correct and the webhook endpoint is properly configured."
}
تحقق حينها مما يلي:
localhost أو العناوين الخاصة. استخدم أداة نفق أثناء التطوير.200 وليس إعادة توجيه إلى صفحة أخرى.{"signature": "..."}، أو قالب HTML يلتف حوله.payload متبوعاً مباشرة بـ timestamp، وباستخدام المفتاح السري لهذا الخطاف.