Headers de autenticación

Con el propósito de reforzar la seguridad y garantizar la integridad del contenido enviado desde el comercio hacia los servicios de nuestra pasarela de pagos, es esencial incorporar ciertos encabezados (header) en cada solicitud al servidor. Para ello, se utiliza el algoritmo SHA-256 en conjunto con HMAC y la llave privada (key) que será proporcionada por el equipo de soporte. Continuación se proporciona una descripción detallada del funcionamiento de este proceso.

Descripción de los encabezados a Agregar

  1. x-scrty-content-sha256: Aplica un algoritmo SHA-256 al cuerpo (body) del request.
  2. x-scrty-date: Representa el tiempo actual en formato UTC (Tiempo Coordinado Universal), expresado en unixtime. Se establece un margen de 5 minutos de diferencia entre el tiempo del encabezado y el tiempo del servidor
  3. Autorization: "scrty: " seguido del cálculo de HMAC, que se detalla a continuación.

Cálculo de HMAC

El proceso de cálculo del hash HMAC se lleva a cabo mediante el algoritmo SHA-256. Este cálculo se realiza sobre la concatenación de los siguientes elementos y la llave privada:

  • method|Content-Type|x-scrty-content-sha256|x-scrty-date

Con el fin de aclarar más el funcionamiento, compartimos el código fuente en algunos lenguajes populares; pero si aún tienes dudas, no dudes en contactar al equipo de soporte.

using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Security.Cryptography;
using System.Text;

class Program
{
    static void Main()
    {
        // Fecha y hora automatizadas
        long date = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
        
        // Clave HMAC
        string key = "XXXXXXXXXXXXXXXXXX";
       
        string transactionBody = "{\"jsonProperty1\": \"value1\", \"jsonProperty2\": \"value2\"}";
        string method = "POST";
        string contentDigest = GetSha256Hash(transactionBody);
        string contentType = "application/json";

        // Nombre del host sin HTTPS
        string host = "urldelendpoint";

        // Encabezados
        Dictionary<string, string> headers = new Dictionary<string, string>
        {
            {"Content-Type", contentType},
            {"Accept", "application/json"},
            {"x-scrty-content-sha256", contentDigest},
            {"x-scrty-date", date.ToString()},
            {"Authorization", "scrty: " + Convert.ToBase64String(HmacSha256(key, $"{method}|{contentType}|{contentDigest}|{date}"))}
        };

        // Solicitud HTTP
        HttpWebRequest request = (HttpWebRequest)WebRequest.Create("https://" + host );
        request.Method = method;
        request.ContentType = contentType;

        foreach (var header in headers)
        {
            request.Headers.Add(header.Key, header.Value);
        }

        using (StreamWriter streamWriter = new StreamWriter(request.GetRequestStream()))
        {
            streamWriter.Write(transactionBody);
            streamWriter.Flush();
            streamWriter.Close();
        }

        // Respuesta HTTP
        HttpWebResponse response = (HttpWebResponse)request.GetResponse();
        using (StreamReader streamReader = new StreamReader(response.GetResponseStream()))
        {
            Console.WriteLine(streamReader.ReadToEnd());
        }
    }

    static string GetSha256Hash(string input)
    {
        using (var sha256 = SHA256.Create())
        {
            byte[] hashBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(input));
            StringSe adjuntan un Builder sb = new StringBuilder();

            foreach (byte b in hashBytes)
            {
                sb.Append(b.ToString("x2"));
            }

            return sb.ToString();
        }
    }

    static byte[] HmacSha256(string key, string data)
    {
        using (HMACSHA256 hmac = new HMACSHA256(Encoding.UTF8.GetBytes(key)))
        {
            return hmac.ComputeHash(Encoding.UTF8.GetBytes(data));
        }
    }
}
import json
import httpx
import hashlib
import hmac
import base64
import time
from fastapi import Response
from app.config import API_BASE_URL, HMAC_KEY

def sha256_hex(data: str) -> str:

    sha256 = hashlib.sha256()
    sha256.update(data.encode("utf-8"))
    return sha256.hexdigest()


def hmac_sha256_base64(message: str, key: str) -> str:
    hmac_bytes = hmac.new(key.encode("utf-8"), message.encode("utf-8"), hashlib.sha256).digest()
    return base64.b64encode(hmac_bytes).decode("utf-8")

def build_auth_headers(method: str, body: str, key: str):

    timestamp = str(int(time.time()))
    body_signed = sha256_hex(body)
    content_type = "" if method == "GET" else "application/json"

    hmac_params = "|".join([
        method.upper(),
        content_type,
        body_signed,
        timestamp
    ])
    authorization = f"scrty: {hmac_sha256_base64(hmac_params, key)}"

    return {
        "x-scrty-content-sha256": body_signed,
        "x-scrty-date": timestamp,
        "Authorization": authorization,
        "Content-Type": content_type
    }

async def forward_request(method: str, endpoint: str, data=None, params=None):
    url = f"{API_BASE_URL}{endpoint}"
    

    if data is None:
        body = None
    else:
        if hasattr(data, "json"):
            body = data.json()
        else:
            body = str(data)

    headers = build_auth_headers(method, body or "", HMAC_KEY)

    async with httpx.AsyncClient(verify=False) as client:

        response = await client.request(
            method, 
            url, 
            json=json.loads(body) if body else None,
            params=params, 
            headers=headers)

        return Response(
            content=response.content,
            status_code=response.status_code,
            media_type=response.headers.get("content-type")
        )