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

# Valida la firma de tu Webhook Endpoint

> Valida el header Fintoc-Signature de cada evento de webhook con HMAC SHA-256 para confirmar que proviene de Fintoc, con ejemplos en Node y Python.

Al final de esta guía, podrás verificar que cada evento de webhook proviene de Fintoc revisando el header `Fintoc-Signature`.

Fintoc firma cada evento enviado a tus webhook endpoints con el header `Fintoc-Signature`. Este header te permite verificar que cada evento recibido fue de hecho enviado por Fintoc y no por un tercero.

Fintoc genera un secreto que se muestra solo una vez al momento del registro de un [webhook endpoint](/es/api/main-resources/webhook-endpoints/webhook-endpoints-create). Este secreto es necesario para validar la firma de Fintoc de cada evento.

## Verifica que los eventos sean enviados por Fintoc

Cada evento enviado por Fintoc incluye el header `Fintoc-Signature`. La estructura del header es la misma para cada evento. Contiene un *timestamp* denotado por la clave `t` y una firma denotada por la clave `v1`. Aquí hay un ejemplo de un header `Fintoc-Signature`:

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

Las firmas enviadas por Fintoc son simplemente códigos HMAC generados al firmar el cuerpo en bruto de la solicitud con la función hash SHA-256 en el momento indicado por el timestamp y usando el secreto del [webhook endpoint](/es/api/main-resources/webhook-endpoints/webhook-endpoints-object).

¡Comencemos a validar la firma del evento!

## Validar la firma usando nuestro SDK

Si estás usando Node o Python, verifica las firmas de los webhooks con nuestro [SDK de Node](https://github.com/fintoc-com/fintoc-node) o [SDK de Python](https://github.com/fintoc-com/fintoc-python).

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

  // Use the secret returned when you created the endpoint
  const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET;

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

  // express.raw keeps req.body as the raw Buffer, which the signature covers.
  app.post('/webhook', express.raw({ type: 'application/json' }), (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...

      // Acknowledge receipt of the event
      res.status(200).json({ received: true });
    } catch (error) {
      if (error instanceof WebhookSignatureError) {
        console.error('Webhook signature verification failed');
        res.status(400).json({
          error: 'Invalid signature',
          message: error.message
        });
      } else {
        res.status(500).json({ error: 'Webhook handler failed' });
      }
    }
  });
  ```

  ```python Python theme={null}
  import os

  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

    # Acknowledge receipt of the event
    return '', 200
  ```
</CodeGroup>

Para un ejemplo completo y funcional, revisa el [código completo aquí](https://github.com/fintoc-com/fintoc-python/blob/master/examples/webhook.py).

## Validar la firma usando tu propio código

Si quieres escribir tu propia implementación o usar un lenguaje de programación distinto, sigue estos pasos:

### Extraer el timestamp y la firma del header

Divide el header `Fintoc-Signature` en un arreglo por el carácter `,`. Luego, divide cada elemento del arreglo generado por el carácter `=` para obtener un par clave-valor. Finalmente, obtén los valores correspondientes para cada clave.

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

### Reconstruir el mensaje firmado

El mensaje que Fintoc firmó antes de enviar el webhook corresponde al timestamp concatenado a un carácter `.` y al cuerpo en bruto de la solicitud. Reconstruyamos ese mismo mensaje usando el timestamp que acabamos de desempaquetar del header `Fintoc-Signature` y el cuerpo en bruto de la solicitud.

```python theme={null}
import json

# Use the Flask request.
message = f"{timestamp}.{request.get_data().decode('utf-8')}"
```

Asegúrate de **usar el cuerpo *raw* de la solicitud** directamente desde la solicitud. Diferentes librerías pueden representar el JSON parseado de manera distinta. Un ejemplo del valor que `message` debería tener sería el siguiente:

```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":"111111111","holder_id":"111111111","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"}'
```

### Generar la firma

Ahora que tienes el mensaje que necesita ser firmado, hagamos justamente eso, usando la función hash SHA-256 y el secreto generado al crear el webhook endpoint.

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

# The secret returned when you created the webhook endpoint
YOUR_WEBHOOK_SECRET = 'YOUR_WEBHOOK_SECRET'
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()
```

### Comparar las firmas

Finalmente, comparemos la firma que desempaquetamos del header `Fintoc-Signature` con la que acabamos de obtener siguiendo los pasos de la guía. Si ambas firmas coinciden, entonces puedes asumir que el evento fue de hecho enviado por Fintoc.

```python theme={null}
import hmac

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

## Prevenir un ataque de replay

Para evitar un ataque de replay, define un rango de tolerancia aceptable para la antigüedad de los eventos. Al recibir un evento, compara el timestamp del header `Fintoc-Signature` con la hora actual. Usa cinco minutos como tolerancia por defecto. Acepta los eventos dentro de ese rango y descarta los que queden fuera.

## Prueba la integración

Confirma que la validación de la firma funciona antes de depender de ella en producción. Genera un evento de prueba para tu webhook endpoint desde el Dashboard de Fintoc y revisa cómo responde tu handler:

* Con una firma válida, tu handler valida el header y procesa el evento.
* Con una firma inválida, por ejemplo un valor `v1` modificado o el secreto incorrecto, tu handler rechaza el evento y retorna `400 Bad Request`.
