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

# Checking Signatures

<Warning>
  In a production setting, it is important to verify signatures sent as part of the webhook payloads. Verifying these signatures ensures that the payloads were sent by One Codex and not a malicious third party.
</Warning>

In addition to the webhook payload body, we include a custom `X-OneCodex-Signature` HTTP header with all delivered webhooks. These signatures are generated using a hash-based message authentication code (HMAC) with SHA-256. Here's an example header:

```
X-OneCodex-Signature: t=1492774577c v1=d929ba98ac0e56ff425f9b8ed7c7ab631dc680f9ea80ce2f604cc75580a63b53
```

Where `t=` provides a Unix timestamp and `v1=` provides the v1 signature (currently the only signature scheme). The signature uses a webhook secret (defaults to the API key for your account) to sign the POST payload body and timestamp. To verify the signature of the payload, you need to:

1. Extract the timestamp and signature from the headers
2. Concatenate the the timestamp and request payload with a `.` to generate a signed payload
3. Determine the expected signature; and finally
4. Verify that the expected signature matches the received signature

Some brief Python 3 code for validating the signature is included for demonstration purposes below:

<CodeGroup>
  ```python python theme={null}
  import hashlib
  import hmac
  import json

  from flask import request

  # Parse the request using your web framework of choice.
  # Note that the entire body of the request is the payload
  # and that you may need to parse the raw request body
  # vs. any loaded JSON in a different language or framework
  # (this code assumes a Python Flask request object).
  payload = request.json
  header = request.headers.get("X-OneCodex-Signature")

  # 1. Extract the timestamp and signature
  timestamp_part = header.split(" ")[0]
  signature_part = header.split(" ")[1]
  if not timestamp_part.startswith("t=") or not signature_part.startswith("v1="):
      raise Exception("Bad signature header format")

  timestamp = int(timestamp_part.split("=")[1])
  signature = signature_part.split("=")[1]

  # 2. Generate a concatenated signed payload
  signed_payload = "%d.%s" % (timestamp, payload)

  # 3. Compute the SHA256 hash of your secret
  secret = hashlib.sha256("YOUR_WEBHOOK_SECRET".encode("utf-8")).hexdigest().encode("utf-8")

  # 4. Determine the expected signature
  expected_signature = hmac.new(
      secret,
      signed_payload.encode(),
      digestmod=hashlib.sha256
  ).hexdigest()

  # 4. Verify that the expected signature matches
  assert expected_signature == signature
  ```
</CodeGroup>

*Note: We use a similar format to [Stripe](https://stripe.com/docs/webhooks/signatures) for our payload signatures (they're the same except Stripe delimits the signed payload and timestamp with a comma vs. a space). See their [rich documentation](https://stripe.com/docs/webhooks/signatures) for additional details on why payload signatures are important and related webhook best practices.*

<Note>
  In the near future, we plan to add support for parsing `Event` objects and verifying the signatures from a webhook payload in our [onecodex](https://github.com/onecodex/onecodex) Python library. This will offer an easy, one line mechanism for verifying payload POST bodies sent by our platform.
</Note>
