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

# Verify webhook requests

> Validate that incoming webhook requests really came from Authsignal.

It is critical to verify that incoming requests to your webhook were sent by Authsignal, and to reject any that were not. The recommended approach is to use an [Authsignal Server SDK](/sdks/server/webhooks) to handle the incoming request.

<CodeGroup>
  ```ts Node.js theme={null}
  const authsignal = new Authsignal({ apiSecretKey: "YOUR_SERVER_API_SECRET_KEY" });

  // Obtain raw request body and signature header
  // For example using Express (https://expressjs.com/)
  const payload = req.body;
  const sig = req.headers["X-Signature-V2"];

  const event = authsignal.webhook.constructEvent(payload, sig);
  ```

  ```csharp C# theme={null}
  var authsignal = new AuthsignalClient("YOUR_SERVER_API_SECRET_KEY");

  // Obtain raw request body and signature header
  var payload = await new StreamReader(HttpContext.Request.Body).ReadToEndAsync();
  var sig = Request.Headers["X-Signature-V2"];

  var webhookEvent = authsignal.Webhook.ConstructEvent(payload, sig);
  ```

  ```java Java theme={null}
  AuthsignalClient authsignal = new AuthsignalClient("YOUR_SERVER_API_SECRET_KEY");

  // Obtain raw request body and signature header
  // For example using the Spark framework (http://sparkjava.com)
  String payload = request.body();
  String sig = request.headers("X-Signature-V2");

  WebhookEvent event = authsignal.webhook.constructEvent(payload, sig);
  ```

  ```ruby Ruby theme={null}
  authsignal = Authsignal::Client.new(api_secret_key: 'YOUR_SERVER_API_SECRET_KEY')

  # Obtain raw request body and signature header
  payload = request.body.read
  sig = request.headers['X-Signature-V2']

  event = authsignal.webhook.construct_event(payload, sig)
  ```

  ```python Python theme={null}
  from authsignal import AuthsignalClient

  authsignal = AuthsignalClient(api_secret_key="YOUR_SERVER_API_SECRET_KEY")

  # Obtain raw request body and signature header
  payload = request.get_data(as_text=True)
  sig = request.headers.get("X-Signature-V2")

  event = authsignal.webhook.construct_event(payload, sig)
  ```

  ```PHP PHP theme={null}
  $authsignal = new Authsignal\Client('YOUR_SERVER_API_SECRET_KEY');

  // Obtain raw request body and signature header
  $payload = file_get_contents('php://input');
  $sig = $_SERVER['HTTP_X_SIGNATURE_V2'];

  $event = $authsignal->webhook()->constructEvent($payload, $sig);
  ```

  ```go Go theme={null}
  webhook := NewWebhook("YOUR_SERVER_API_SECRET_KEY")

  // Obtain raw request body and signature header
  payload := string(body)
  sig := r.Header.Get("X-Signature-V2")

  event, err := webhook.ConstructEventWithDefaultTolerance(payload, sig)
  ```
</CodeGroup>

By passing the raw request body along with the `X-Signature-V2` header to the SDK, it verifies that the request is valid and constructs the event for you to handle.

<Warning>
  The Authsignal SDK requires the **raw body** of the request to verify the signature. If you're
  using a framework, make sure it doesn't manipulate the raw body, as this will cause the signature
  verification to fail.
</Warning>

## Replay protection

The Authsignal Server SDKs reject events older than **5 minutes** by default. Customize the window by passing a `tolerance` value (in minutes).

<CodeGroup>
  ```ts Node.js theme={null}
  const payload = req.body;
  const sig = req.headers["X-Signature-V2"];
  const tolerance = 10;

  const event = authsignal.webhook.constructEvent(payload, sig, tolerance);
  ```

  ```csharp C# theme={null}
  var payload = await new StreamReader(HttpContext.Request.Body).ReadToEndAsync();
  var sig = Request.Headers["X-Signature-V2"];
  var tolerance = 10;

  var webhookEvent = authsignal.Webhook.ConstructEvent(payload, sig, tolerance);
  ```

  ```java Java theme={null}
  String payload = request.body();
  String sig = request.headers("X-Signature-V2");
  int tolerance = 10;

  WebhookEvent event = authsignal.webhook.constructEvent(payload, sig, tolerance);
  ```

  ```ruby Ruby theme={null}
  payload = request.body.read
  sig = request.headers['X-Signature-V2']
  tolerance = 10

  event = authsignal.webhook.construct_event(payload, sig, tolerance)
  ```

  ```python Python theme={null}
  payload = request.get_data(as_text=True)
  sig = request.headers.get("X-Signature-V2")
  tolerance = 10

  event = authsignal.webhook.construct_event(payload, sig, tolerance)
  ```

  ```PHP PHP theme={null}
  $payload = file_get_contents('php://input');
  $sig = $_SERVER['HTTP_X_SIGNATURE_V2'];
  $tolerance = 10;

  $event = $authsignal->webhook()->constructEvent($payload, $sig, $tolerance);
  ```

  ```go Go theme={null}
  payload := string(body)
  sig := r.Header.Get("X-Signature-V2")
  tolerance := 10

  event, err := webhook.ConstructEvent(payload, sig, tolerance)
  ```
</CodeGroup>
