Authentication Without Email / Password
Obtaining Authentication Keys
Client Id and Client Secret are available over the merchant portal in the Settings menu.

Authentication
Encryption is done using AES algorithm with PKCS7 padding, CBC mode and a key size of 256. Encryption of the body payload is as follows:-
var CryptoJS = require('crypto-js');
var data = CryptoJS.AES.encrypt(JSON.stringify({
merchantId: 'MERCHANT_ID',
totp:''
}), 'CLIENT_SECRET').toString();
pm.variables.set("encryptedPayload", data);from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
import hashlib
import base64
def generate_salt():
return get_random_bytes(8)
def evpkdf(passphrase, salt, key_size=32, iv_size=16):
"""
Derives a key and IV from the passphrase and salt using OpenSSL compatible method.
"""
d = d_i = b'' # Initialize empty bytes for key and IV derivation
while len(d) < key_size + iv_size:
d_i = hashlib.md5(d_i + passphrase.encode('utf-8') + salt).digest()
d += d_i
return d[:key_size], d[key_size:key_size + iv_size]
def pad(data):
"""Pads data to a multiple of AES block size (16 bytes)."""
padding_len = 16 - len(data) % 16
return data + chr(padding_len) * padding_len
def encrypt_data(data, passphrase, salt):
key, iv = evpkdf(passphrase, salt)
cipher = AES.new(key, AES.MODE_CBC, iv)
encrypted_data = cipher.encrypt(pad(data).encode())
return encrypted_data
def create_encrypted_payload(data, passphrase):
salt = generate_salt()
encrypted_data = encrypt_data(data, passphrase, salt)
encrypted_data_with_salt = b"Salted__" + salt + encrypted_data
return base64.b64encode(encrypted_data_with_salt).decode('utf-8')
# Data to be encrypted
data = {
'merchantId': MERCHANT_ID,
'totp': ''
}
# Convert the data to a JSON string
data_str = json.dumps(data)
# Create the encrypted payload
encrypted_payload = create_encrypted_payload(data_str, CLIENT_SECRET)function encrypt($toEncrypt, $secret){
$salt = openssl_random_pseudo_bytes(8);
$salted = $dx = '';
while (strlen($salted) < 48) {
$dx = md5($dx . $secret . $salt, true);
$salted .= $dx;
}
$key = substr($salted, 0, 32);
$iv = substr($salted, 32, 16);
// encrypt with PKCS7 padding
return base64_encode('Salted__' . $salt . openssl_encrypt($toEncrypt . '', 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv));
}using System;
using System.Security.Cryptography;
using System.Text;
using System.Linq;
public class EncryptionAES
{
private static readonly Random SecureRandom = new Random();
public static byte[] EvpKDF(byte[] password, byte[] salt, int keySize = 48, string hasher = "MD5", int iterations = 1)
{
byte[] keyMaterial = new byte[keySize];
int generatedBytes = 0;
byte[] block = null;
using (var md = MD5.Create())
{
while (generatedBytes < keySize)
{
md.Initialize();
if (block != null)
md.TransformBlock(block, 0, block.Length, null, 0);
md.TransformBlock(password, 0, password.Length, null, 0);
md.TransformFinalBlock(salt, 0, salt.Length);
block = md.Hash;
for (int i = 1; i < iterations; i++)
{
block = md.ComputeHash(block);
}
int remaining = Math.Min(block.Length, keySize - generatedBytes);
Array.Copy(block, 0, keyMaterial, generatedBytes, remaining);
generatedBytes += remaining;
}
}
return keyMaterial;
}
public static string EncryptAES(string data, string key)
{
using (var aes = Aes.Create())
{
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
byte[] salt = new byte[8];
SecureRandom.NextBytes(salt);
byte[] derivedKey = EvpKDF(Encoding.UTF8.GetBytes(key), salt);
byte[] keyBytes = derivedKey.Take(32).ToArray();
byte[] ivBytes = derivedKey.Skip(32).Take(16).ToArray();
aes.Key = keyBytes;
aes.IV = ivBytes;
using (var encryptor = aes.CreateEncryptor())
using (var ms = new System.IO.MemoryStream())
{
ms.Write(Encoding.ASCII.GetBytes("Salted__"), 0, 8);
ms.Write(salt, 0, salt.Length);
using (var cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
using (var sw = new System.IO.StreamWriter(cs))
{
sw.Write(data);
}
return Convert.ToBase64String(ms.ToArray());
}
}
}
}
//how to use
var data = new { merchantId = "861331d4-aa85-42c2-8a4f-a8e78043809a",totp=""};
string toEncrypt = JsonSerializer.Serialize(data);
string secret = "SECRET";
string encrypted = EncryptionAES.EncryptAES(toEncrypt, secret);
Console.WriteLine("Encrypted: " + encrypted);/**
* based on: www.openssl.org/docs/crypto/EVP_BytesToKey.html
*/
fun evpKDF(password: ByteArray, salt: ByteArray, keySize: Int = 48, hasher: String = "MD5", iterations: Int = 1): ByteArray {
val keyMaterial = ByteArray(keySize)
var generatedBytes = 0
var block: ByteArray? = null
val md = MessageDigest.getInstance(hasher)
while (generatedBytes < keySize) {
md.reset()
if (block != null)
md.update(block)
md.update(password)
block = md.digest(salt)
for (i in 1 until iterations)
block = md.digest(block)
val remaining = block!!.size.coerceAtMost(keySize - generatedBytes)
System.arraycopy(block, 0, keyMaterial, generatedBytes, remaining)
generatedBytes += remaining
}
return keyMaterial
}
fun encryptAES(data: String, key: String): String {
val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
val salt = ByteArray(8)
secureRandom.nextBytes(salt)
val derivedKey = evpKDF(key.toByteArray(), salt)
val secretKey = SecretKeySpec(derivedKey.sliceArray(0..31), "AES")
val iv = IvParameterSpec(derivedKey.sliceArray(32..47))
cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv)
val encrypted = cipher.doFinal(data.toByteArray())
val encryptedWithIv = "Salted__".toByteArray() + salt + encrypted
return Base64.getEncoder().encodeToString(encryptedWithIv)
}Generating access and refresh token using encrypted payload and clientId
POST api/auth/generate-auth-token
This endpoint is used for generating access and refresh tokens without using merchant email and password. It requires clientId and encrypted string generated from the encryption logic discussed above.
Request Body
Name
Type
Description
clientId*
String
Client Id can be accessed in Settings menu
encryptedPayload*
String
AES encrypted (using client secret) payload containing merchant Id and totp
{
"ok": true,
"result": {
"access": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImM1MzlkZWVjLTYwNDktNDZlMC1hZTJjLTUwZTJhNjQ2ZmMzMSIsImlhdCI6MTY2MjczOTczOSwiZXhwIjoxNjYyODI2MTM5fQ.AkvmP2oTAfj91w5w9arOAsiAAnfg1o-Ia-3b3PkZSaw",
"refresh": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImM1MzlkZWVjLTYwNDktNDZlMC1hZTJjLTUwZTJhNjQ2ZmMzMSIsImlhdCI6MTY2MjczOTczOSwiZXhwIjoxNjY1MzMxNzM5fQ.CFjoO4XwZpuQNBpkVoQtpUbu1_yYVIFoMO5MqDWYGeg",
"status": 2
}
}Last updated
Was this helpful?