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

# Rotacionar chave secreta de assinatura

> Rotacione com segurança a chave secreta de assinatura do seu webhook com uma janela de tolerância de assinatura dupla de 24 horas

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

## Visão geral

O Ayrshare assina cada entrega de webhook com um [HMAC-SHA256](https://en.wikipedia.org/wiki/HMAC) do payload, tendo como chave sua **chave secreta de assinatura**, para que seu receptor possa confirmar que a entrega realmente veio do Ayrshare. Consulte [Segurança do webhook](/docs/apis/webhooks/overview#webhook-security) para entender como a verificação funciona.

Rotacionar sua chave secreta de assinatura permite substituí-la em uma programação regular, ou imediatamente se você suspeitar que ela foi exposta. Para tornar a rotação segura, o Ayrshare abre uma **janela de tolerância de 24 horas** após cada rotação, durante a qual as entregas são assinadas com **ambas** a sua chave secreta anterior e a nova. Isso permite que você atualize seu receptor no seu próprio ritmo, sem descartar ou rejeitar uma única entrega — o mesmo padrão usado por Stripe e GitHub.

<Note>
  A chave secreta de assinatura é **por profile**: há uma chave secreta por User Profile (UID),
  e ela assina **todas** as ações de webhook que aquele profile tem registradas. Não há
  chave secreta de assinatura por ação — definir ou rotacionar a chave secreta a altera para todas as
  ações daquele profile ao mesmo tempo.
</Note>

## Rotacionar pelo painel

Você pode definir ou rotacionar sua chave secreta de assinatura na [página Webhooks](https://app.ayrshare.com/webhooks) do Painel do Desenvolvedor. O painel **Signing Secret** aparece acima da sua lista de webhooks assim que o profile tem pelo menos um webhook registrado.

<Steps>
  <Step title="Abra o painel Signing Secret">
    Acesse a [página Webhooks](https://app.ayrshare.com/webhooks). Se ainda não houver chave secreta configurada, o painel exibe **No signing secret configured** com um botão **Set Signing Secret**. Se já houver uma configurada, ele exibe **Signing secret configured** com um botão **Rotate**.
  </Step>

  <Step title="Definir ou rotacionar">
    Clique em **Set Signing Secret** (primeira vez) ou **Rotate** (chave secreta existente). Um modal se abre com uma chave secreta forte, gerada aleatoriamente, pré-preenchida e revelada. Você pode **Copy** (copiar), **Regenerate** (regerar) uma nova, ou alternar **paste my own** para fornecer seu próprio valor.
  </Step>

  <Step title="Confirmar">
    Copie a chave secreta para um local seguro — ela é exibida apenas uma vez e nunca mais pode ser recuperada pela interface — e então confirme para enviar. Uma notificação de sucesso aparece e o painel é atualizado.
  </Step>

  <Step title="Atualize seu receptor">
    Em uma rotação (não em uma primeira definição), o painel exibe um indicador da janela de tolerância ativa e o botão **Rotate** fica desabilitado até que a janela se feche. Você tem 24 horas para implantar a nova chave secreta no seu receptor.
  </Step>
</Steps>

## Rotacionar pela API

Rotacione (ou defina) a chave secreta de assinatura com uma única chamada. Isso cria uma nova chave secreta, aponta a referência de chave secreta do profile para ela e — quando uma chave secreta existente já estava em vigor — registra a chave secreta substituída como a chave secreta anterior com expiração em 24 horas.

### Parâmetros do cabeçalho

<HeaderAPI />

### Parâmetros do corpo

<ParamField body="secret" type="string" required>
  O valor da nova chave secreta de assinatura. Qualquer string não vazia é aceita. Recomendamos um valor aleatório longo e de alta entropia (por exemplo, 32 bytes aleatórios codificados em 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>

O `secret` em texto claro **nunca** é retornado na resposta e nunca é registrado em logs. A resposta traz o `refId` voltado ao cliente (um hash do UID), nunca o UID em si. O cabeçalho `Profile-Key` é opcional e limita a rotação a um único User Profile para contas com múltiplos profiles.

Um `secret` ausente ou vazio retorna um erro mapeado (`code: 101`, "Missing/incorrect parameter") com status HTTP `400`, e nenhuma alteração é feita na sua chave secreta atual. Uma primeira definição pela API (sem chave secreta existente) cria a chave secreta sem chave secreta anterior registrada e sem janela de tolerância.

## Procedimento de rotação segura

Por causa da janela de tolerância de 24 horas, não há uma ordem obrigatória de operações — seu receptor continua funcionando durante todo o processo. A sequência recomendada é:

<Steps>
  <Step title="Rotacione a chave secreta">
    Rotacione pelo painel ou pela API. O Ayrshare imediatamente começa a assinar as entregas com ambas as suas chaves secretas, a anterior e a nova.
  </Step>

  <Step title="Atualize seu receptor">
    Em até 24 horas, implante a nova chave secreta no seu receptor de webhook para que ele verifique contra o novo valor.
  </Step>

  <Step title="Deixe a janela se fechar">
    Após 24 horas, o Ayrshare limpa automaticamente a chave secreta anterior e assina somente com a nova chave secreta. Nenhuma ação adicional é necessária do seu lado.
  </Step>
</Steps>

<Tip>
  Se você rotacionar novamente enquanto uma janela de tolerância ainda estiver aberta, a
  chave secreta recém-substituída torna-se a nova chave secreta anterior e uma nova janela de 24 horas
  começa. Apenas uma chave secreta anterior é mantida por vez.
</Tip>

## Verificando assinaturas durante a janela de tolerância

Fora de uma janela de tolerância, as entregas assinadas carregam os cabeçalhos padrão (consulte [Segurança do 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>
```

Durante a janela de 24 horas após uma rotação, o novo cabeçalho `X-Authorization-Content-SHA256-V2` lista **ambas** as assinaturas, a atual primeiro, separadas por vírgula:

```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` permanece inalterado: ele sempre carrega o único
  HMAC da chave secreta atual, por compatibilidade retroativa. Assinaturas duplas aparecem apenas no
  novo cabeçalho `X-Authorization-Content-SHA256-V2`.
</Note>

Cada valor em `X-Authorization-Content-SHA256-V2` é prefixado com uma tag de esquema. `v1=` denota uma assinatura HMAC-SHA256, calculada exatamente como `X-Authorization-Content-SHA256`. O cabeçalho `-V2` está sempre presente sempre que uma entrega é assinada — ele carrega ao menos `v1=<current-sig>` — para que você possa contar com ele como um contrato estável para o receptor.

Para verificar uma entrega durante (ou fora de) uma rotação:

<Steps>
  <Step title="Calcule o HMAC">
    Calcule o HMAC-SHA256 do **corpo bruto da requisição** usando a chave secreta de assinatura configurada localmente.
  </Step>

  <Step title="Compare com cada assinatura listada">
    Leia `X-Authorization-Content-SHA256-V2`, divida-o pelas vírgulas, remova o prefixo `v1=` de cada valor e aceite a entrega como autêntica se o HMAC calculado corresponder a **qualquer** assinatura `v1=` listada.
  </Step>
</Steps>

Aceitar quando **qualquer** assinatura listada corresponder é o que torna a rotação sem tempo de inatividade: um receptor ainda configurado com a chave secreta antiga corresponde a `v1=<previous-sig>`, enquanto um receptor atualizado para a nova chave secreta corresponde a `v1=<current-sig>` — ambos têm sucesso durante toda a janela.

### Exemplo de verificação no receptor

```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>
  Sempre calcule o HMAC sobre os bytes **brutos** do corpo da requisição, exatamente como
  recebidos — não sobre um objeto JSON re-serializado. A re-serialização pode alterar
  espaços em branco ou a ordem das chaves e quebrar a verificação. Use uma comparação em tempo constante
  (como `crypto.timingSafeEqual`) para evitar ataques de temporização.
</Warning>

Se o registro da chave secreta atual de uma entrega estiver ausente, a entrega prossegue **sem assinatura** (sem cabeçalhos de assinatura) em vez de falhar. Se apenas o registro da chave secreta anterior tiver desaparecido, a assinatura anterior é ignorada e a assinatura atual ainda é emitida em ambos os cabeçalhos.
