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

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/reference/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/reference/main-resources/webhook-endpoints/webhook-endpoints-object).

¡Comencemos a validar la firma del evento!

# Validar la firma usando nuestro SDK

Si estás usando Python o Node, la forma más fácil de verificar las firmas de los webhooks es con nuestro [SDK de Python](https://github.com/fintoc-com/fintoc-python) o [SDK de Node](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
```

```node 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
    }
  }
});
 
```

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}
# using 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

# using 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":"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"}'
```

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

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, recomendamos que definas un rango de tolerancia para los retrasos de los eventos. Al recibir y obtener el timestamp de un evento, verifica que caiga dentro de tu rango de tolerancia. Si ese no es el caso, descarta el evento.
