> For the complete documentation index, see [llms.txt](https://docs.rocketfuel.inc/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.rocketfuel.inc/developer-guides/api-reference/payins/authentication/authentication-without-email-password.md).

# Authentication Without Email / Password

### Obtaining Authentication Keys

Client Id and Client Secret are available over the merchant portal in the Settings menu.

<figure><img src="/files/YkpOFOLxOSzNWgqfr2xP" alt=""><figcaption></figcaption></figure>

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

{% tabs %}
{% tab title="Javascript" %}

```javascript
var CryptoJS = require('crypto-js');
var data = CryptoJS.AES.encrypt(JSON.stringify({
    merchantId: 'MERCHANT_ID',
    totp:''
}), 'CLIENT_SECRET').toString();

pm.variables.set("encryptedPayload", data);
```

{% endtab %}

{% tab title="Python" %}

```python
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)
```

{% endtab %}

{% tab title="PHP" %}

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

{% endtab %}

{% tab title="C#" %}

```csharp
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);
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
If we provide the clientSecret as string it will not use it as a key but a passphrase to derive the key value using a KDF. The default KDF for this library is similar to the open SSL EVP function. (for reference: <https://www.openssl.org/docs/manmaster/man3/EVP_BytesToKey.html>) This function generates the actual AES keys using MD5 hashing and uses 1 iteration.
{% endhint %}

```kotlin
/**
* 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

<mark style="color:green;">`POST`</mark> `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.&#x20;

#### Request Body

| Name                                               | Type   | Description                                                                 |
| -------------------------------------------------- | ------ | --------------------------------------------------------------------------- |
| clientId<mark style="color:red;">\*</mark>         | String | Client Id can be accessed in Settings menu                                  |
| encryptedPayload<mark style="color:red;">\*</mark> | String | AES encrypted (using client secret) payload containing merchant Id and totp |

{% tabs %}
{% tab title="200: OK " %}

```javascript
{
    "ok": true,
    "result": {
        "access": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImM1MzlkZWVjLTYwNDktNDZlMC1hZTJjLTUwZTJhNjQ2ZmMzMSIsImlhdCI6MTY2MjczOTczOSwiZXhwIjoxNjYyODI2MTM5fQ.AkvmP2oTAfj91w5w9arOAsiAAnfg1o-Ia-3b3PkZSaw",
        "refresh": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImM1MzlkZWVjLTYwNDktNDZlMC1hZTJjLTUwZTJhNjQ2ZmMzMSIsImlhdCI6MTY2MjczOTczOSwiZXhwIjoxNjY1MzMxNzM5fQ.CFjoO4XwZpuQNBpkVoQtpUbu1_yYVIFoMO5MqDWYGeg",
        "status": 2
    }
}
```

{% endtab %}
{% endtabs %}
