Buscar en la documentación
ctrl+4K
Módulos
Authentication
Merchant
Catalog
Order
Events
Logistics
Shipping
Review
Financial
Soluciones

Visión general

Las URLs de webhooks quedan expuestas en internet. Para garantizar que una request realmente vino de iFood, implementamos el header X-IFood-Signature en todas las requests de webhook. Este header permite validar la autenticidad de los mensajes recibidos.Rechaza requests con firmas inválidas. Esta validación es obligatoria para la homologación del webhook. iFood puede enviar eventos con firmas inválidas para probar tu integración. Esta verificación también protege contra fraudes. Auditamos todos los eventos entregados, los intentos de entrega y los eventos descartados.

Validación

El webhook usa (HMAC) con SHA256 para firmar cada mensaje. El valor final se codifica en hexadecimal. La firma usa el client secret de la aplicación (el mismo utilizado para generar tokens), disponible en la pestaña "Credenciales" del Portal del Desarrollador. Cada request incluye esta firma en el header X-IFood-Signature. Para validar, genera el HMAC del mensaje recibido usando tu secret (en lugar seguro) y compara con la firma recibida usando comparación segura (ejemplo). La mayoría de los lenguajes tienen bibliotecas con soporte nativo:
Los campos pueden ser agregados a cualquier evento en cualquier momento, sin causar breaking change. Por eso, valida la firma antes de convertir el contenido del mensaje en objeto. Genera la firma usando el byte array del body exactamente como fue recibido.Este cuidado es esencial en JSON, ya que {"prop1": "value1", "prop2": "value2"} y {"prop2": "value2", "prop1": "value1"} son equivalentes para parsers, pero forman byte arrays diferentes. Los caracteres especiales también pueden variar conforme a la biblioteca o lenguaje.

Ejemplos

Todos los ejemplos son válidos para el mismo JSON, pero con diferentes formatos y deben ser soportados por tu integración:
{
    "code":"PLC",
    "createdAt":"2023-02-20T18:19:03.20162269Z",
    "fullCode":"PLACED",
    "id":"a38ba215-f949-4b2c-982a-0582a9d0c10e",
    "merchantId":"cad65e8f-6fc6-438a-b159-e64a902a6b9a",
    "orderId":"2c97e104-35ed-4c18-85d7-854a40b6b9e3"
}
Los ejemplos muestran cómo el formato afecta la firma:
X-IFood-Signature: 6f9ed23a7b505a3b6907c5f6eb2ad1b056fbf35a643d365a9a072ed7aabca153. Payload:
{"code":"PLC","createdAt":"2023-02-20T18:19:03.20162269Z","fullCode":"PLACED","id":"a38ba215-f949-4b2c-982a-0582a9d0c10e","merchantId":"cad65e8f-6fc6-438a-b159-e64a902a6b9a","orderId":"2c97e104-35ed-4c18-85d7-854a40b6b9e3"}
'X-IFood-Signature: cf7e092c9148a48f5ee5f12b947f46b331eac6bf0745e1e1d0f3df722e219df3'. Payload:
{ "code":"PLC", "createdAt":"2023-02-20T18:19:03.20162269Z", "fullCode":"PLACED", "id":"a38ba215-f949-4b2c-982a-0582a9d0c10e", "merchantId":"cad65e8f-6fc6-438a-b159-e64a902a6b9a", "orderId":"2c97e104-35ed-4c18-85d7-854a40b6b9e3" }
'X-IFood-Signature: adf5446334f754e73588f3ae10b308306307f0c797f7f678912d740c6deddf6a'. Payload:
{
    "code":"PLC",
    "createdAt":"2023-02-20T18:19:03.20162269Z",
    "fullCode":"PLACED",
    "id":"a38ba215-f949-4b2c-982a-0582a9d0c10e",
    "merchantId":"cad65e8f-6fc6-438a-b159-e64a902a6b9a",
    "orderId":"2c97e104-35ed-4c18-85d7-854a40b6b9e3"
}
X-IFood-Signature: e2d26f22f89932ff3d23a699031b22d6f30323501430dc08c3a971dd875e23b5. Payload:
{"merchantId":"cad65e8f-6fc6-438a-b159-e64a902a6b9a","orderId":"2c97e104-35ed-4c18-85d7-854a40b6b9e3","code":"PLC","createdAt":"2023-02-20T18:19:03.20162269Z","fullCode":"PLACED","id":"a38ba215-f949-4b2c-982a-0582a9d0c10e"}
Sigue un snippet Java de cómo hacer la validación del mensaje:
private String bytesToHexString(byte[] bytes) {
    var sb = new StringBuilder();
    for (var b : bytes) {
        var hex = String.format("%02x", b);
        sb.append(hex);
    }
    return sb.toString();
}

private boolean verifyHmacSHA256(String secret, String data, String expectedSignature) {
    try {
        var mac = Mac.getInstance("HmacSHA256");
        var secretKeySpec = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
        mac.init(secretKeySpec);
        var hmacBytes = mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
        return bytesToHexString(hmacBytes).equals(expectedSignature);
    } catch (NoSuchAlgorithmException | InvalidKeyException e) {
        return false;
    }
}
Ve un ejemplo del snippet de un endpoint en Go:
http.HandleFunc("/webhook", func(w http.ResponseWriter, r *http.Request) {
  body, err := io.ReadAll(r.Body)
  if err != nil {
    fmt.Printf("could not read body")
    w.WriteHeader(400)
    return
  }

  headerSignature := r.Header.Get("X-IFood-Signature")

  signature, err := hex.DecodeString(headerSignature)
  if err != nil {
    panic(err)
  }

  hasher := hmac.New(sha256.New, SECRET)
  hasher.Write(body)
  expected := hasher.Sum(nil)

  if !hmac.Equal(expected, signature) {
    fmt.Printf("invalid signature")
    w.WriteHeader(401)
    return
  }

  // Message validated...
})

Ve también

¿Esta página fue útil?
Evalúa tu experiencia en el nuevo portal de desarrolladores: