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

# Validate the signature of your webhook endpoint

> Validate the Fintoc-Signature header on webhook events sent by Fintoc's legacy v2023-11-15 API using HMAC SHA-256, with Node and Python code examples.

Fintoc signs every event sent to your webhook endpoints with the `Fintoc-Signature` header. Use this header to verify that an event came from Fintoc, not a third party.

Fintoc generates a secret when you register a webhook endpoint. Fintoc shows this secret only once. Use the secret to validate each event's signature.

# Verify that events come from Fintoc

Each event sent by Fintoc includes the `Fintoc-Signature` header. The header contains a Unix timestamp under the `t` key and a signature under the `v1` key:

```text theme={null}
t=1620870928,v1=4df951e02db34a3f333bccad26d207993e9b14d78ac77cec026091991f567f6d
```

Fintoc generates each signature as a hash-based message authentication code (HMAC). Fintoc signs the timestamp and raw request body with the webhook endpoint secret and the SHA-256 hash function.

# Validate the signature with an SDK

If you use Python or Node, verify webhook signatures with the [Python SDK](https://github.com/fintoc-com/fintoc-python) or [Node SDK](https://github.com/fintoc-com/fintoc-node).

```python Python theme={null}
from fintoc.webhook import WebhookSignature
from fintoc.errors import WebhookSignatureError

WEBHOOK_SECRET = os.getenv('FINTOC_WEBHOOK_SECRET')

# Rest of your code 
# ...

@app.route('/webhook', methods=['POST'])
def handle_webhook():
  # Get the signature header
  signature = request.headers.get('Fintoc-Signature')

  # Get the raw request payload
  payload = request.get_data().decode('utf-8')

  # Verify the webhook signature
  try:
    WebhookSignature.verify_header(
      payload=payload,
      header=signature,
      secret=WEBHOOK_SECRET
    )

  except WebhookSignatureError as e:
    print('Invalid signature!')
    return str(e), 400
```

```javascript Node theme={null}
const { WebhookSignature, WebhookSignatureError } = require('fintoc');

// Find your endpoint's secret in your webhook settings in the Fintoc Dashboard
const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET;

// Rest of your code here
// ...

app.post('/webhook', (req, res) => {
  const payload = req.body;
  
  // Get the signature header
  const signature = req.headers['fintoc-signature'];

  try {
    // Verify the webhook signature
    WebhookSignature.verifyHeader(
      payload,
      signature,
      WEBHOOK_SECRET
    );

    // If verification passes, process the webhook
    const event = JSON.parse(payload.toString());
    
    // Rest of your code...


  } catch (error) {
    if (error instanceof WebhookSignatureError) {
      console.error('Webhook signature verification failed');
      res.status(400).json({
        error: 'Invalid signature',
        message: error.message
      });
    } else {
      // Other error
    }
  }
});
 
```

For a complete working example, see the [Python webhook example](https://github.com/fintoc-com/fintoc-python/blob/master/examples/webhook.py).

# Validate the signature with your code

If you want to write your own implementation or use a different programming language, follow these steps:

## Extract the timestamp and signature

Split the `Fintoc-Signature` header at the `,` character. Then, split each resulting element at the `=` character to obtain the key-value pairs. Extract the value for each key.

```python theme={null}
# using flask request
header_value = request.headers.get('Fintoc-Signature')
timestamp, event_signature = [x.split('=')[1] for x in header_value.split(',')]
```

## Rebuild the signed message

Fintoc signs a message composed of the timestamp, a `.` character, and the raw request body. Rebuild this message with the timestamp from the `Fintoc-Signature` header and the raw request body.

```python theme={null}
import json

# using flask request
message = f"{timestamp}.{request.get_data().decode('utf-8')}"
```

Use the **raw request body** directly from the request. Libraries can represent parsed JSON differently. The value of `message` has the following format:

```python theme={null}
'1626102791.{"id":"evt_DyzYBwdC07ao5MqG","type":"link.credentials_changed","mode":"test","created_at":"2021-07-12T15:11:09.875Z","data":{"id":"link_00000000","mode":"test","active":true,"object":"link","status":"active","accounts":null,"username":"416148503","holder_id":"416148503","created_at":"2021-06-24T00:00:00.000Z","link_token":null,"holder_type":"individual","institution":{"id":"cl_banco_bbva","name":"Banco BBVA","country":"cl"}},"object":"event"}'
```

## Generate the signature

Sign the message with the SHA-256 hash function and the secret generated when you created the webhook endpoint.

```python theme={null}
import hmac
from hashlib import sha256

encoded_secret = YOUR_WEBHOOK_SECRET.encode('utf-8')
encoded_message = message.encode('utf-8')
hmac_object = hmac.new(encoded_secret, msg=encoded_message, digestmod=sha256)
signature = hmac_object.hexdigest()
```

## Compare the signatures

Compare the signature from the `Fintoc-Signature` header with the signature you generated. If the signatures match, you can confirm that Fintoc sent the event.

```python theme={null}
import hmac

valid_signature = hmac.compare_digest(signature, event_signature)
```

# Prevent replay attacks

To prevent replay attacks, define a tolerance range for event delivery delays. When you receive an event, verify that its timestamp falls within this range. Discard the event if its timestamp falls outside the range.
