Skip to main content

Autenticación HMAC

La API de PAGO46 utiliza autenticación HMAC como protocolo de seguridad entre la comunicación de clientes y la API. El protocolo HMAC consiste en crear un hash basado en cierta información y debe ser generado para cada request y enviado con el mismo. Cada request a la API P46 debe enviar los parámetros provider-key, message-hash y message-date como cabecera. Estos parámetros se generan basado en la información del request, por ende, cada hash es único por request y no debe ser reutilizado por otros request futuros porque no será válido.

Generación de Hash#

Pasos para generaración de hash :

  • Tener credenciales para comunicación con API (Provider Key y Provider Secret). Si no tiene esta información, favor contacte a su ejecutivo comercial.
  • Generar timestamp (datetime) el cual se debe mandar como cabecera y también es usado para generar el hash.
  • Generar un hash HMAC SHA256 con el Provider Secret como password y como contenido un texto con el siguiente formato providerKey + '&' + date + '&' + requestMethod + '&' + requestPath + concatenatedParams donde:
    • providerKey: Provider Key
    • date: Unix Timestamp en milisegundos generado previamente (13 dígitos). El mismo valor deberá adjuntarse posteriormente como cabecera message-date.
    • requestMethod: GET, POST, PUT o DELETE dependiendo del caso.
    • requestPath: Solo path de la URL, encodeada (URL Encoded) a la cual se hará el request. Ejemplo: Si la url es https://api.pago46.io/payments/provider/ solo se debe utilizar %2Fpayments%2Fprovider%2F.
    • concatenatedParams: Todos los parámetros necesarios a enviar (no cabeceras) concatenados en formato URL alfabéticamente por key y el valor con URL Encoded.
  • Adjuntar hash resultando como cabecera message-hash también el Unix timestamp utilizado para el hash como message-date y el Provider Key como provider-key. Adicionalmente mandar todos los parámetros necesarios en el body o url del request dependiendo del caso.

Ejemplo Python#

Envio único de transacción#

A continuación se presenta un ejemplo en lenguaje Python donde se genera una hash HMAC para el endpoint que permite añadir una transferencia bancaria. En este caso múltiples parámetros son necesarios en body que deben ser considerados en la generación del hash por request.

createOrder.py
import hashlib
import hmac
import urllib
import time
from collections import OrderedDict
class RequestAuth:
@staticmethod
def get_concatenated_payload(payload):
"""Concatenate payload"""
concatenated_data = ''
params = OrderedDict(sorted(payload.items()))
for key, value in params.items():
concatenated_data += "&" + \
urllib.parse.quote(key, safe='') + "=" + \
urllib.parse.quote(str(value), safe='')
return concatenated_data
def sign_request(self, method, path, provider_key, provider_secret, payload):
"""sign a request to CPP of PAGO46"""
date = str(time.time()).replace('.', '')
encrypt_base = provider_key + '&' + date + '&' + \
method + '&' + urllib.parse.quote(str(path), safe='')
if len(payload) > 0:
encrypt_base += self.get_concatenated_payload(payload)
message_hash = hmac.new(provider_secret.encode('utf-8'), encrypt_base.encode('utf-8'),
hashlib.sha256).hexdigest()
return message_hash, date

Transacción en bulto#

A continuación se presenta un ejemplo en lenguaje Python donde se genera una hash HMAC para el endpoint que permite añadir transferencias bancarias en bulto. En este caso múltiples parámetros son necesarios en body que deben ser considerados en la generación del hash por request.

createOrder.py
class RequestAuth:
"""
Class with main purpose of creating the Authentication needed to access any endpoint in Destroyer.
"""
def get_concatenated_payload(self, payload, sort_payload=True):
"""
Check if the payload is a list with multiple transactions (dict) or if
it is a single transaction, depending on that, concatenate the
corresponding information.
"""
payload_is_list = True if isinstance(payload, list) else False
concatenated_payload = ''
if payload_is_list:
for ind in payload:
concatenated_payload = self.concatenate_payload(ind, concatenated_payload, sort=sort_payload)
else:
concatenated_payload = self.concatenate_payload(payload, concatenated_payload, sort=sort_payload)
return concatenated_payload
@staticmethod
def concatenate_payload(dicionary: dict, concatenated_data: str, sort: bool):
"""Concatenate payload"""
params = OrderedDict(sorted(dicionary.items())) if sort else OrderedDict(dicionary.items())
for key, value in params.items():
concatenated_data += "&" + urllib.parse.quote(key, safe='') + \
"=" + urllib.parse.quote(str(value), safe='')
return concatenated_data
def sign_request(self, method, path, provider_key, provider_secret, payload):
"""sign a request to CPP of PAGO46"""
date = str(time.time()).replace('.', '')
encrypt_base = provider_key + '&' + date + '&' + \
method + '&' + urllib.parse.quote(str(path), safe='')
if len(payload) > 0:
encrypt_base += self.get_concatenated_payload(payload)
message_hash = hmac.new(provider_secret.encode('utf-8'), encrypt_base.encode('utf-8'),
hashlib.sha256).hexdigest()
return message_hash, date