> ## Documentation Index
> Fetch the complete documentation index at: https://www.ayrshare.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# تدوير المفتاح السري للتوقيع

> قم بتدوير المفتاح السري لتوقيع webhook بأمان مع نافذة سماح للتوقيع المزدوج مدتها 24 ساعة

export const PlansAvailable = ({plans = [], maxPackRequired}) => {
  let displayPlans = plans;
  if (plans && plans.length === 1) {
    const lowerCasePlan = plans[0].toLowerCase();
    if (lowerCasePlan === "business") {
      displayPlans = ["Launch", "Business", "Enterprise"];
    } else if (lowerCasePlan === "premium") {
      displayPlans = ["Premium", "Launch", "Business", "Enterprise"];
    }
  }
  return <Note>
Available on {displayPlans.length === 1 ? "the " : ""}
{displayPlans.join(", ").replace(/\b\w/g, l => l.toUpperCase())}{" "}
{displayPlans.length > 1 ? "plans" : "plan"}.

{maxPackRequired && <span onClick={() => window.open('https://www.ayrshare.com/docs/additional/maxpack', '_self')} className="flex items-center mt-2 cursor-pointer">
 <span className="px-1.5 py-0.5 rounded text-sm" style={{
    backgroundColor: '#C264B6',
    color: 'white',
    fontSize: '12px'
  }}>
   Max Pack required
 </span>
</span>}
</Note>;
};

export const HeaderAPI = ({noProfileKey, profileKeyRequired}) => <>
    <ParamField header="Authorization" type="string" required>
      <a href="/docs/apis/overview#authorization">API Key</a> of the Primary Profile.
      <br />
      <br />
      Format: <code>Authorization: Bearer API_KEY</code>
    </ParamField>
    {!noProfileKey && (profileKeyRequired ? <ParamField header="Profile-Key" type="string" required>
          <a href="/docs/apis/overview#profile-key-format">Profile Key</a> of a User Profile.
          <br />
          <br />
          Format: <code>Profile-Key: PROFILE_KEY</code>
        </ParamField> : <ParamField header="Profile-Key" type="string">
          <a href="/docs/apis/overview#profile-key-format">Profile Key</a> of a User Profile.
          <br />
          <br />
          Format: <code>Profile-Key: PROFILE_KEY</code>
        </ParamField>)}
  </>;

<PlansAvailable plans={["premium"]} maxPackRequired={false} />

## نظرة عامة

توقّع Ayrshare كل تسليم webhook باستخدام [HMAC-SHA256](https://en.wikipedia.org/wiki/HMAC) لحمولة الطلب، مُفتاحًا بالمفتاح **السري للتوقيع** الخاص بك، حتى يتمكن المستقبل لديك من تأكيد أن التسليم صادر فعليًا من Ayrshare. راجع [أمان Webhook](/docs/apis/webhooks/overview#webhook-security) لمعرفة كيفية عمل التحقق.

يتيح لك تدوير المفتاح السري للتوقيع استبداله وفق جدول منتظم، أو فورًا إذا اشتبهت في أنه تعرض للكشف. لجعل التدوير آمنًا، تفتح Ayrshare **نافذة سماح مدتها 24 ساعة** بعد كل عملية تدوير، تُوقَّع خلالها التسليمات باستخدام **كل من** مفتاحك السري السابق ومفتاحك الجديد. يتيح لك هذا تحديث المستقبل الخاص بك وفق جدولك الخاص دون إسقاط أو رفض أي تسليم — وهو النمط ذاته المستخدم من قِبل Stripe وGitHub.

<Note>
  المفتاح السري للتوقيع يعمل **على مستوى الملف الشخصي**: هناك مفتاح سري واحد لكل User Profile (UID)،
  ويوقّع **كل** إجراء webhook مُسجَّل لهذا الملف الشخصي. لا يوجد مفتاح سري
  للتوقيع خاص بكل إجراء — تعيين المفتاح السري أو تدويره يغيّره لجميع
  الإجراءات على هذا الملف الشخصي دفعة واحدة.
</Note>

## التدوير من لوحة التحكم

يمكنك تعيين أو تدوير المفتاح السري للتوقيع من [صفحة Webhooks](https://app.ayrshare.com/webhooks) في Developer Dashboard. تظهر لوحة **Signing Secret** فوق قائمة webhooks الخاصة بك بمجرد أن يمتلك الملف الشخصي webhook واحدًا مُسجَّلًا على الأقل.

<Steps>
  <Step title="افتح لوحة Signing Secret">
    انتقل إلى [صفحة Webhooks](https://app.ayrshare.com/webhooks). إذا لم يكن هناك مفتاح سري مُهيَّأ بعد، تعرض اللوحة **No signing secret configured** مع زر **Set Signing Secret**. إذا كان هناك مفتاح مُهيَّأ بالفعل، تعرض **Signing secret configured** مع زر **Rotate**.
  </Step>

  <Step title="تعيين أو تدوير">
    انقر على **Set Signing Secret** (للمرة الأولى) أو **Rotate** (لمفتاح سري موجود). ينفتح مربع حوار مع مفتاح سري قوي مولَّد عشوائيًا معبّأ مسبقًا ومكشوف. يمكنك **Copy** له، أو **Regenerate** واحدًا جديدًا، أو تبديل **paste my own** لتوفير قيمتك الخاصة.
  </Step>

  <Step title="أكّد">
    انسخ المفتاح السري في مكان آمن — يُعرض مرة واحدة فقط ولا يمكن استرجاعه من واجهة المستخدم أبدًا مرة أخرى — ثم أكّد للإرسال. تظهر رسالة نجاح وتُحدَّث اللوحة.
  </Step>

  <Step title="حدّث المستقبل الخاص بك">
    عند التدوير (وليس التعيين لأول مرة)، تعرض اللوحة مؤشر نافذة سماح نشطة ويكون زر **Rotate** معطلًا حتى تُغلَق النافذة. لديك 24 ساعة لنشر المفتاح السري الجديد إلى المستقبل الخاص بك.
  </Step>
</Steps>

## التدوير عبر API

قم بتدوير (أو تعيين) المفتاح السري للتوقيع بمكالمة واحدة. يؤدي هذا إلى إنشاء مفتاح سري جديد، وإعادة توجيه مرجع المفتاح السري للملف الشخصي إليه، و — عندما يكون هناك مفتاح سري موجود — يسجّل المفتاح السري المُستبدَل كمفتاح سري سابق مع انتهاء صلاحية بعد 24 ساعة.

### معاملات الترويسة

<HeaderAPI />

### معاملات النص

<ParamField body="secret" type="string" required>
  قيمة المفتاح السري الجديد للتوقيع. يُقبل أي سلسلة نصية غير فارغة. نوصي بقيمة عشوائية طويلة وعالية الإنتروبيا (على سبيل المثال، 32 بايت عشوائية مُرمَّزة بـ base64url).
</ParamField>

<RequestExample>
  ```bash cURL theme={"system"}
  curl --request POST \
    --url https://api.ayrshare.com/api/hook/webhook/secret \
    --header 'Authorization: Bearer YOUR_API_KEY' \
    --header 'Content-Type: application/json' \
    --header 'Profile-Key: YOUR_PROFILE_KEY' \
    --data '{
      "secret": "your-new-signing-secret"
    }'
  ```
</RequestExample>

<ResponseExample>
  ```json 200: Response theme={"system"}
  {
    "status": "success",
    "action": "webhook",
    "refId": "3dc079614bdc3f281d9" // User Profile Ref Id
  }
  ```
</ResponseExample>

لا يُعاد المفتاح `secret` بنصه الصريح **أبدًا** في الاستجابة ولا يُسجَّل مطلقًا. تحمل الاستجابة `refId` الموجَّه للعميل (تجزئة لـ UID)، وليس UID ذاته أبدًا. ترويسة `Profile-Key` اختيارية وتُقصر التدوير على User Profile واحد للحسابات متعددة الملفات الشخصية.

يُعيد الغياب أو الفراغ في `secret` خطأً معيّنًا (`code: 101`، "Missing/incorrect parameter") مع حالة HTTP `400`، ولا يُجرى أي تغيير على مفتاحك السري الحالي. يؤدي التعيين لأول مرة عبر API (بدون مفتاح سري موجود) إلى إنشاء المفتاح السري دون تسجيل مفتاح سري سابق ودون نافذة سماح.

## إجراء التدوير الآمن

بفضل نافذة السماح التي مدتها 24 ساعة، لا يوجد ترتيب مطلوب للعمليات — يستمر المستقبل الخاص بك في العمل طوال الوقت. التسلسل الموصى به هو:

<Steps>
  <Step title="تدوير المفتاح السري">
    قم بالتدوير من لوحة التحكم أو عبر API. تبدأ Ayrshare فورًا في توقيع التسليمات باستخدام كل من مفتاحك السري السابق ومفتاحك الجديد.
  </Step>

  <Step title="حدّث المستقبل الخاص بك">
    خلال 24 ساعة، انشر المفتاح السري الجديد إلى مستقبل webhook الخاص بك حتى يتحقق مقابل القيمة الجديدة.
  </Step>

  <Step title="اترك النافذة تُغلق">
    بعد 24 ساعة، تمسح Ayrshare تلقائيًا المفتاح السري السابق وتوقّع فقط بالمفتاح السري الجديد. لا يلزم اتخاذ أي إجراء إضافي من جانبك.
  </Step>
</Steps>

<Tip>
  إذا قمت بالتدوير مرة أخرى بينما لا تزال نافذة السماح مفتوحة، يصبح المفتاح
  السري الذي تم استبداله للتو هو المفتاح السري السابق الجديد وتبدأ نافذة جديدة
  مدتها 24 ساعة. يُحتفظ بمفتاح سري سابق واحد فقط في كل مرة.
</Tip>

## التحقق من التوقيعات خلال نافذة السماح

خارج نافذة السماح، تحمل التسليمات الموقّعة الترويسات القياسية (راجع [أمان Webhook](/docs/apis/webhooks/overview#webhook-security)):

```bash theme={"system"}
X-Authorization-Timestamp : <Unix Timestamp In Seconds>
X-Authorization-Content-SHA256 : <current-sig>
X-Authorization-Content-SHA256-V2 : v1=<current-sig>
```

خلال نافذة الـ 24 ساعة بعد التدوير، تُدرج ترويسة `X-Authorization-Content-SHA256-V2` الجديدة **كلا** التوقيعين، الحالي أولًا، مفصولين بفاصلة:

```bash theme={"system"}
X-Authorization-Timestamp : <Unix Timestamp In Seconds>
X-Authorization-Content-SHA256 : <current-sig>
X-Authorization-Content-SHA256-V2 : v1=<current-sig>,v1=<previous-sig>
```

<Note>
  `X-Authorization-Content-SHA256` لم تتغير: تحمل دائمًا HMAC للمفتاح السري الحالي
  المفرد، للتوافق مع الإصدارات السابقة. لا تظهر التوقيعات المزدوجة إلا في
  ترويسة `X-Authorization-Content-SHA256-V2` الجديدة.
</Note>

يُسبق كل قيمة في `X-Authorization-Content-SHA256-V2` بوسم مخطط. يشير `v1=` إلى توقيع HMAC-SHA256، مُحسَب تمامًا مثل `X-Authorization-Content-SHA256`. تكون ترويسة `-V2` موجودة دائمًا كلما تم توقيع تسليم — إذ تحمل على الأقل `v1=<current-sig>` — لذا يمكنك الاعتماد عليها كعقد مستقبل مستقر.

للتحقق من تسليم أثناء (أو خارج) عملية تدوير:

<Steps>
  <Step title="احسب HMAC">
    احسب HMAC-SHA256 لـ **نص الطلب الخام** باستخدام المفتاح السري للتوقيع المُهيَّأ محليًا لديك.
  </Step>

  <Step title="قارن مقابل كل توقيع مُدرج">
    اقرأ `X-Authorization-Content-SHA256-V2`، وقسّمها على الفواصل، وأزل بادئة `v1=` من كل قيمة، واقبل التسليم كأصلي إذا تطابق HMAC المحسوب لديك مع **أي** توقيع `v1=` مُدرج.
  </Step>
</Steps>

القبول عند تطابق **أي** توقيع مُدرج هو ما يجعل التدوير بدون توقف: المستقبل الذي لا يزال مُهيَّأً بالمفتاح السري القديم يتطابق مع `v1=<previous-sig>`، بينما المستقبل الذي جرى تحديثه إلى المفتاح السري الجديد يتطابق مع `v1=<current-sig>` — كلاهما ينجح طوال النافذة.

### مثال على التحقق في المستقبل

```javascript Node.js theme={"system"}
import crypto from "crypto";

// secret is the signing secret currently configured on your receiver.
function isAuthenticWebhook(rawBody, headers, secret) {
  const expected = crypto
    .createHmac("sha256", secret)
    .update(rawBody) // the raw, unparsed request body
    .digest("hex");

  const headerValue = headers["x-authorization-content-sha256-v2"] || "";

  // Accept if ANY v1= signature in the header matches our computed HMAC.
  return headerValue
    .split(",")
    .map((part) => part.trim())
    .filter((part) => part.startsWith("v1="))
    .map((part) => part.slice("v1=".length))
    .some((sig) => {
      const sigBuf = Buffer.from(sig);
      const expectedBuf = Buffer.from(expected);
      // timingSafeEqual throws on length mismatch — treat as not authentic.
      return (
        sigBuf.length === expectedBuf.length &&
        crypto.timingSafeEqual(sigBuf, expectedBuf)
      );
    });
}
```

<Warning>
  احسب دائمًا HMAC على بايتات نص الطلب **الخام**، تمامًا كما استُلمت —
  وليس على كائن JSON مُعاد التسلسل. قد تُغيّر إعادة التسلسل المسافات البيضاء أو
  ترتيب المفاتيح وتُبطل التحقق. استخدم مقارنة بزمن ثابت (مثل
  `crypto.timingSafeEqual`) لتجنب هجمات التوقيت.
</Warning>

إذا كان سجل المفتاح السري الحالي للتسليم مفقودًا، يمضي التسليم **غير موقّع** (بدون ترويسات توقيع) بدلًا من الفشل. إذا كان سجل المفتاح السري السابق فقط مفقودًا، يُتخطى التوقيع السابق ويُصدَر التوقيع الحالي مع ذلك في كلتا الترويستين.
