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

# Signing Secret rotieren

> Rotieren Sie Ihr Webhook-Signing-Secret sicher mit einem 24-Stunden-Dual-Signing-Grace-Fenster

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

## Überblick

Ayrshare signiert jede Webhook-Zustellung mit einem [HMAC-SHA256](https://en.wikipedia.org/wiki/HMAC) des Payloads unter Verwendung Ihres **Signing Secrets**, damit Ihr Empfänger bestätigen kann, dass eine Zustellung tatsächlich von Ayrshare stammt. Wie die Verifizierung funktioniert, sehen Sie unter [Webhook-Sicherheit](/docs/apis/webhooks/overview#webhook-security).

Durch das Rotieren Ihres Signing Secrets können Sie es regelmäßig oder umgehend austauschen, wenn Sie vermuten, dass es kompromittiert wurde. Damit die Rotation sicher ist, öffnet Ayrshare nach jeder Rotation ein **24-Stunden-Grace-Fenster**, in dem Zustellungen mit **beiden**, dem bisherigen und dem neuen Secret, signiert werden. So können Sie Ihren Empfänger in Ihrem eigenen Tempo aktualisieren, ohne eine einzige Zustellung zu verlieren oder abzulehnen – dasselbe Muster, das auch Stripe und GitHub verwenden.

<Note>
  Das Signing Secret gilt **profilweit**: Es gibt ein Secret pro User Profile (UID),
  und es signiert **jede** Webhook-Aktion, die dieses Profil registriert hat. Es gibt kein
  Signing Secret pro Aktion – das Setzen oder Rotieren des Secrets ändert es für alle
  Aktionen dieses Profils gleichzeitig.
</Note>

## Über das Dashboard rotieren

Sie können Ihr Signing Secret auf der [Webhooks-Seite](https://app.ayrshare.com/webhooks) im Developer Dashboard setzen oder rotieren. Das Panel **Signing Secret** erscheint oberhalb Ihrer Webhook-Liste, sobald das Profil mindestens einen registrierten Webhook besitzt.

<Steps>
  <Step title="Signing-Secret-Panel öffnen">
    Öffnen Sie die [Webhooks-Seite](https://app.ayrshare.com/webhooks). Wenn noch kein Secret konfiguriert ist, zeigt das Panel **No signing secret configured** mit einer Schaltfläche **Set Signing Secret**. Ist bereits eines konfiguriert, zeigt es **Signing secret configured** mit einer Schaltfläche **Rotate**.
  </Step>

  <Step title="Setzen oder Rotieren">
    Klicken Sie auf **Set Signing Secret** (erstmalig) oder **Rotate** (bestehendes Secret). Ein Modal öffnet sich mit einem starken, zufällig generierten und bereits sichtbaren Secret. Sie können es **Copy**ieren, ein neues **Regenerate**n oder **paste my own** umschalten, um Ihren eigenen Wert anzugeben.
  </Step>

  <Step title="Bestätigen">
    Kopieren Sie das Secret an einen sicheren Ort – es wird nur einmal angezeigt und kann nicht erneut aus der UI abgerufen werden – und bestätigen Sie dann das Absenden. Ein Erfolgs-Toast erscheint und das Panel wird aktualisiert.
  </Step>

  <Step title="Ihren Empfänger aktualisieren">
    Bei einer Rotation (nicht bei erstmaligem Setzen) zeigt das Panel eine aktive Grace-Window-Anzeige und die **Rotate**-Schaltfläche ist deaktiviert, bis das Fenster schließt. Sie haben 24 Stunden Zeit, das neue Secret auf Ihrem Empfänger auszurollen.
  </Step>
</Steps>

## Über die API rotieren

Rotieren (oder setzen) Sie das Signing Secret mit einem einzigen Aufruf. Dabei wird ein neues Secret erzeugt, die Secret-Referenz des Profils darauf umgestellt und – falls ein bestehendes Secret vorhanden war – das ersetzte Secret als vorheriges Secret mit einer Ablaufzeit von 24 Stunden vermerkt.

### Header-Parameter

<HeaderAPI />

### Body-Parameter

<ParamField body="secret" type="string" required>
  Der neue Wert des Signing Secrets. Jeder nicht leere String wird akzeptiert. Wir empfehlen einen langen, zufälligen Wert mit hoher Entropie (zum Beispiel 32 zufällige Bytes als base64url kodiert).
</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>

Das Klartext-`secret` wird **niemals** in der Antwort zurückgegeben und niemals geloggt. Die Antwort enthält die clientseitige `refId` (einen Hash der UID), niemals die UID selbst. Der `Profile-Key`-Header ist optional und begrenzt die Rotation bei Multi-Profile-Konten auf ein einzelnes User Profile.

Ein fehlendes oder leeres `secret` gibt einen gemappten Fehler zurück (`code: 101`, „Missing/incorrect parameter") mit HTTP-Status `400`, und Ihr aktuelles Secret bleibt unverändert. Ein erstmaliges Setzen über die API (kein bestehendes Secret) legt das Secret an, ohne dass ein vorheriges Secret erfasst wird und ohne Grace-Fenster.

## Sichere Rotationsprozedur

Dank des 24-Stunden-Grace-Fensters gibt es keine zwingende Reihenfolge – Ihr Empfänger funktioniert die ganze Zeit weiter. Die empfohlene Reihenfolge lautet:

<Steps>
  <Step title="Secret rotieren">
    Rotieren Sie über das Dashboard oder die API. Ayrshare beginnt sofort damit, Zustellungen mit beiden Secrets zu signieren – dem bisherigen und dem neuen.
  </Step>

  <Step title="Empfänger aktualisieren">
    Rollen Sie das neue Secret innerhalb von 24 Stunden auf Ihrem Webhook-Empfänger aus, damit dieser gegen den neuen Wert verifiziert.
  </Step>

  <Step title="Fenster schließen lassen">
    Nach 24 Stunden entfernt Ayrshare das vorherige Secret automatisch und signiert nur noch mit dem neuen Secret. Auf Ihrer Seite ist keine weitere Aktion nötig.
  </Step>
</Steps>

<Tip>
  Wenn Sie erneut rotieren, während noch ein Grace-Fenster offen ist, wird das gerade
  ersetzte Secret zum neuen vorherigen Secret, und ein frisches 24-Stunden-Fenster
  beginnt. Es wird immer nur ein vorheriges Secret zur Zeit vorgehalten.
</Tip>

## Signaturen während des Grace-Fensters verifizieren

Außerhalb eines Grace-Fensters tragen signierte Zustellungen die Standard-Header (siehe [Webhook-Sicherheit](/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>
```

Während des 24-Stunden-Fensters nach einer Rotation listet der neue Header `X-Authorization-Content-SHA256-V2` **beide** Signaturen, aktuelle zuerst, kommagetrennt:

```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` bleibt unverändert: Er trägt aus Gründen der
  Rückwärtskompatibilität immer den einzelnen HMAC des aktuellen Secrets. Doppelte
  Signaturen erscheinen nur im neuen Header `X-Authorization-Content-SHA256-V2`.
</Note>

Jeder Wert in `X-Authorization-Content-SHA256-V2` ist mit einem Scheme-Tag versehen. `v1=` bezeichnet eine HMAC-SHA256-Signatur, die genauso berechnet wird wie `X-Authorization-Content-SHA256`. Der `-V2`-Header ist immer vorhanden, wann immer eine Zustellung signiert wird – er trägt mindestens `v1=<current-sig>` –, sodass Sie sich als Empfänger auf ihn als stabilen Vertrag verlassen können.

So verifizieren Sie eine Zustellung während (oder außerhalb) einer Rotation:

<Steps>
  <Step title="HMAC berechnen">
    Berechnen Sie den HMAC-SHA256 des **rohen Request-Bodys** mit Ihrem lokal konfigurierten Signing Secret.
  </Step>

  <Step title="Gegen jede gelistete Signatur vergleichen">
    Lesen Sie `X-Authorization-Content-SHA256-V2`, splitten Sie an Kommas, entfernen Sie das `v1=`-Präfix von jedem Wert und akzeptieren Sie die Zustellung als authentisch, wenn Ihr berechneter HMAC mit **irgendeiner** gelisteten `v1=`-Signatur übereinstimmt.
  </Step>
</Steps>

Dass eine Übereinstimmung mit **irgendeiner** gelisteten Signatur ausreicht, macht die Rotation ausfallfrei: Ein Empfänger, der noch mit dem alten Secret konfiguriert ist, matcht `v1=<previous-sig>`, während ein bereits auf das neue Secret aktualisierter Empfänger `v1=<current-sig>` matcht – beide sind während des gesamten Fensters erfolgreich.

### Beispiel für die Empfänger-Verifizierung

```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>
  Berechnen Sie den HMAC immer über die **rohen** Request-Body-Bytes, genauso wie
  empfangen – nicht über ein neu serialisiertes JSON-Objekt. Neuserialisierung kann
  Whitespace oder Schlüsselreihenfolge verändern und die Verifizierung brechen.
  Verwenden Sie einen konstanten Zeitvergleich (etwa `crypto.timingSafeEqual`),
  um Timing-Angriffe zu vermeiden.
</Warning>

Falls bei einer Zustellung der Datensatz des aktuellen Secrets fehlt, wird die Zustellung **unsigniert** (ohne Signatur-Header) fortgesetzt statt zu scheitern. Fehlt nur der Datensatz des vorherigen Secrets, wird die vorherige Signatur übersprungen und die aktuelle Signatur wird weiterhin in beiden Headern ausgeliefert.
