> ## 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.

# Rotate Signing Secret

> 24-घंटे dual-signing grace window के साथ अपने webhook signing secret को सुरक्षित रूप से rotate करें

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} />

## Overview

Ayrshare हर webhook delivery को payload के [HMAC-SHA256](https://en.wikipedia.org/wiki/HMAC) से sign करता है, जो आपके **signing secret** द्वारा keyed होता है, ताकि आपका receiver पुष्टि कर सके कि delivery वास्तव में Ayrshare से आई है। सत्यापन कैसे काम करता है, इसके लिए [Webhook Security](/docs/apis/webhooks/overview#webhook-security) देखें।

अपने signing secret को rotate करने से आप इसे नियमित रूप से, या यदि आपको संदेह है कि यह उजागर हो गया है तो तुरंत बदल सकते हैं। Rotation को सुरक्षित बनाने के लिए, Ayrshare हर rotation के बाद एक **24-घंटे का grace window** खोलता है जिसके दौरान deliveries आपके पिछले **और** आपके नए secret **दोनों** से signed होती हैं। यह आपको एक भी delivery को drop या reject किए बिना अपने receiver को अपने शेड्यूल पर अपडेट करने देता है — वही pattern जो Stripe और GitHub उपयोग करते हैं।

<Note>
  Signing secret **profile-wide** होता है: प्रति User Profile (UID) एक secret होता है,
  और यह उस profile ने जो **हर** webhook action रजिस्टर किया है, उसे sign करता है। कोई
  per-action signing secret नहीं है — secret को सेट या rotate करने से उस profile के सभी
  actions के लिए यह एक साथ बदल जाता है।
</Note>

## Dashboard से Rotate करें

आप Developer Dashboard में [Webhooks page](https://app.ayrshare.com/webhooks) से अपने signing secret को सेट या rotate कर सकते हैं। **Signing Secret** panel आपकी webhook सूची के ऊपर तब दिखाई देता है जब profile में कम से कम एक रजिस्टर किया गया webhook हो।

<Steps>
  <Step title="Signing Secret panel खोलें">
    [Webhooks page](https://app.ayrshare.com/webhooks) पर जाएँ। यदि अभी तक कोई secret configured नहीं है, तो panel **No signing secret configured** एक **Set Signing Secret** बटन के साथ दिखाता है। यदि एक पहले से configured है, तो यह **Signing secret configured** एक **Rotate** बटन के साथ दिखाता है।
  </Step>

  <Step title="Set या Rotate">
    **Set Signing Secret** (पहली बार) या **Rotate** (मौजूदा secret) पर क्लिक करें। एक modal खुलता है जिसमें एक strong, यादृच्छिक रूप से जनरेट किया गया secret pre-filled और प्रकट होता है। आप इसे **Copy** कर सकते हैं, एक नया **Regenerate** कर सकते हैं, या अपना स्वयं का मान देने के लिए **paste my own** को टॉगल कर सकते हैं।
  </Step>

  <Step title="Confirm">
    Secret को कहीं सुरक्षित स्थान पर कॉपी करें — इसे केवल एक बार दिखाया जाता है और इसे UI से फिर कभी पुनः प्राप्त नहीं किया जा सकता — फिर submit करने के लिए confirm करें। एक success toast दिखाई देता है और panel अपडेट हो जाता है।
  </Step>

  <Step title="अपने receiver को अपडेट करें">
    Rotation पर (पहली बार सेट नहीं), panel एक active grace-window indicator दिखाता है और **Rotate** बटन तब तक disabled रहता है जब तक window बंद नहीं हो जाती। आपके पास नए secret को अपने receiver पर डिप्लॉय करने के लिए 24 घंटे हैं।
  </Step>
</Steps>

## API के माध्यम से Rotate करें

एकल कॉल के साथ signing secret को rotate (या set) करें। यह एक नया secret बनाता है, profile के secret reference को इस पर repoint करता है, और — जब एक मौजूदा secret था — supersede किए गए secret को 24 घंटे बाद expiry के साथ previous secret के रूप में रिकॉर्ड करता है।

### Header Parameters

<HeaderAPI />

### Body Parameters

<ParamField body="secret" type="string" required>
  नया signing secret मान। कोई भी non-empty string स्वीकार किया जाता है। हम एक long, high-entropy random मान की सिफारिश करते हैं (उदाहरण के लिए, base64url के रूप में एन्कोड किए गए 32 random bytes)।
</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>

Plaintext `secret` **कभी भी** response में नहीं लौटाया जाता और कभी log नहीं किया जाता। Response में client-facing `refId` (UID का एक hash) होता है, कभी भी UID स्वयं नहीं। `Profile-Key` header वैकल्पिक है और multi-profile accounts के लिए rotation को एकल User Profile तक सीमित करता है।

एक missing या empty `secret` एक mapped error (`code: 101`, "Missing/incorrect parameter") HTTP `400` status के साथ लौटाता है, और आपके वर्तमान secret में कोई परिवर्तन नहीं किया जाता। API के माध्यम से पहली बार सेट (कोई मौजूदा secret नहीं) बिना कोई previous secret रिकॉर्ड किए और बिना grace window के secret बनाता है।

## सुरक्षित Rotation प्रक्रिया

24-घंटे के grace window के कारण, संचालनों का कोई आवश्यक क्रम नहीं है — आपका receiver इस दौरान काम करता रहता है। अनुशंसित क्रम है:

<Steps>
  <Step title="Secret को rotate करें">
    Dashboard से या API के माध्यम से rotate करें। Ayrshare तुरंत आपके पिछले और आपके नए secret दोनों से deliveries को sign करना शुरू कर देता है।
  </Step>

  <Step title="अपने receiver को अपडेट करें">
    24 घंटे के भीतर, नए secret को अपने webhook receiver पर डिप्लॉय करें ताकि यह नए मान के विरुद्ध सत्यापित करे।
  </Step>

  <Step title="Window को बंद होने दें">
    24 घंटे के बाद, Ayrshare स्वचालित रूप से previous secret को clear कर देता है और केवल नए secret से sign करता है। आपकी ओर से किसी और कार्रवाई की आवश्यकता नहीं है।
  </Step>
</Steps>

<Tip>
  यदि आप एक grace window के अभी भी open रहते हुए फिर से rotate करते हैं, तो अभी-अभी
  supersede किया गया secret नया previous secret बन जाता है और एक नया 24-घंटे का window
  शुरू होता है। एक समय में केवल एक previous secret रखा जाता है।
</Tip>

## Grace Window के दौरान Signatures का सत्यापन

एक grace window के बाहर, signed deliveries standard headers ले जाती हैं (देखें [Webhook Security](/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>
```

Rotation के बाद 24-घंटे के window के दौरान, नया `X-Authorization-Content-SHA256-V2` header **दोनों** signatures सूचीबद्ध करता है, current पहले, comma-separated:

```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` अपरिवर्तित है: यह हमेशा एकल current-secret HMAC ले
  जाता है, backward compatibility के लिए। Dual signatures केवल नए
  `X-Authorization-Content-SHA256-V2` header में दिखाई देते हैं।
</Note>

`X-Authorization-Content-SHA256-V2` में प्रत्येक मान एक scheme tag के साथ prefixed है। `v1=` एक HMAC-SHA256 signature को दर्शाता है, जो ठीक `X-Authorization-Content-SHA256` की तरह गणना की जाती है। `-V2` header हमेशा तब मौजूद रहता है जब कोई delivery signed होती है — यह कम से कम `v1=<current-sig>` ले जाता है — इसलिए आप इसे एक stable receiver contract के रूप में उपयोग कर सकते हैं।

Rotation के दौरान (या बाहर) एक delivery को सत्यापित करने के लिए:

<Steps>
  <Step title="HMAC की गणना करें">
    अपने locally configured signing secret का उपयोग करके **raw request body** का HMAC-SHA256 गणना करें।
  </Step>

  <Step title="प्रत्येक सूचीबद्ध signature के विरुद्ध तुलना करें">
    `X-Authorization-Content-SHA256-V2` पढ़ें, इसे commas पर विभाजित करें, प्रत्येक मान से `v1=` prefix हटाएँ, और यदि आपका गणना किया गया HMAC **किसी भी** सूचीबद्ध `v1=` signature से मेल खाता है तो delivery को authentic के रूप में स्वीकार करें।
  </Step>
</Steps>

**किसी भी** सूचीबद्ध signature के मेल खाने पर स्वीकार करना ही rotation को zero-downtime बनाता है: पुराने secret के साथ अभी भी configured एक receiver `v1=<previous-sig>` से मेल खाता है, जबकि नए secret पर अपडेट किया गया receiver `v1=<current-sig>` से मेल खाता है — window के दौरान दोनों सफल होते हैं।

### Receiver सत्यापन उदाहरण

```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 की गणना **raw** request body bytes पर करें, ठीक वैसे ही जैसे प्राप्त हुए
  — न कि किसी re-serialized JSON object पर। Re-serialization whitespace या key order
  को बदल सकता है और सत्यापन को तोड़ सकता है। Timing attacks से बचने के लिए एक
  constant-time तुलना (जैसे `crypto.timingSafeEqual`) का उपयोग करें।
</Warning>

यदि किसी delivery का current secret record गायब है, तो delivery विफल होने के बजाय **unsigned** (कोई signature headers नहीं) आगे बढ़ती है। यदि केवल previous secret record गायब है, तो previous signature को छोड़ दिया जाता है और current signature अभी भी दोनों headers में emit की जाती है।
