> ## Documentation Index
> Fetch the complete documentation index at: https://rain-sandbox-trial.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Use Encryption Outside a Browser Environment

> Alternative encryption and decryption implementations for server-side environments using Node.js.

<Warning>
  **Security best practices:**

  * Never store decrypted card details.
  * Only request full card details when absolutely necessary.
  * Always use the latest encryption libraries to maintain security.
</Warning>

## Step 1: Generating the session ID

Use the `generateSessionID` method to generate the `SessionId`. This ensures that only the correct user can decrypt the data. You'll need the [public RSA key for your environment](/docs/resource-sessionid-keys):

### Requirements

* The secret must be a 32-character hexadecimal string with no spaces or dashes.
* Encryption must use RSA-OAEP padding with the provided public key.

### Example session ID generation

<CodeGroup>
  ```js theme={null}
  import crypto from "crypto";

  async function generateSessionId(pem, secret) {
    if (!pem) throw new Error("pem is required");
    if (secret && !/^[0-9A-Fa-f]+$/.test(secret)) {
      throw new Error("secret must be a hex string");
    }

    const secretKey = secret ?? crypto.randomUUID().replace(/-/g, "");
    const secretKeyBase64 = Buffer.from(secretKey, "hex").toString("base64");
    const secretKeyBase64Buffer = Buffer.from(secretKeyBase64, "utf-8");
    const secretKeyBase64BufferEncrypted = crypto.publicEncrypt(
      {
        key: pem,
        padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
        oaepHash: 'sha1'
      },
      secretKeyBase64Buffer,
    );

    return {
      secretKey,
      sessionId: secretKeyBase64BufferEncrypted.toString("base64"),
    };
  }
  ```
</CodeGroup>

* The `sessionId` is required to make an API request.
* The `secretKey` will be needed for decryption later.

## Step 2: Sending the API request

Once the `sessionId` is generated, you can send a request to retrieve encrypted card details.

### Requesting encrypted card details

Send a request to the [get a card's encrypted data](/reference/cards/get-a-cards-encrypted-data) endpoint.

### Example API request

<CodeGroup>
  ```bash bash theme={null}
  curl --request GET \
       --url https://api-dev.rain.xyz/v1/issuing/cards/cardId/secrets \
       --header 'SessionId: sessionId' \
       --header 'accept: application/json'
  ```
</CodeGroup>

### Example API response

<CodeGroup>
  ```json theme={null}
  {
    "encryptedPan": {
      "iv": "base64_iv_string",
      "data": "base64_encrypted_pan"
    },
    "encryptedCvc": {
      "iv": "base64_iv_string",
      "data": "base64_encrypted_cvc"
    }
  }
  ```
</CodeGroup>

## Step 3: Decrypting the encrypted card data

To decrypt the received encrypted card details, use AES-128-GCM decryption.

### Example card data decryption

<CodeGroup>
  ```js theme={null}
  import crypto from "crypto";

  async function decryptSecret(base64Secret, base64Iv, secretKey) {
    if (!base64Secret) throw new Error("base64Secret is required");
    if (!base64Iv) throw new Error("base64Iv is required");
    if (!secretKey || !/^[0-9A-Fa-f]+$/.test(secretKey)) {
      throw new Error("secretKey must be a hex string");
    }

    const secret = Buffer.from(base64Secret, "base64");
    const iv = Buffer.from(base64Iv, "base64");
    const secretKeyBuffer = Buffer.from(secretKey, "hex");
    
  	 // AES-GCM typically uses a 128-bit (16-byte) authentication tag
    const tagLength = 16;

    // Separate the ciphertext from the authentication tag
    const ciphertext = secret.subarray(0, -tagLength);
    const authTag = secret.subarray(-tagLength);

    const cryptoKey = crypto.createDecipheriv("aes-128-gcm", secretKeyBuffer, iv);
    cryptoKey.setAutoPadding(false);

    const decrypted = cryptoKey.update(secret);
    
    return decrypted.toString("utf-8").trim();
  }
  ```
</CodeGroup>

### Example final output

<CodeGroup>
  ```js theme={null}
  const decryptedCardNumber = await decryptSecret(data.encryptedPan.data, data.encryptedPan.iv, secretKey);
  const decryptedCVC = await decryptSecret(data.encryptedCvc.data, data.encryptedCvc.iv, secretKey);

  console.log("Decrypted Card Number:", decryptedCardNumber);
  console.log("Decrypted CVC:", decryptedCVC);
  ```
</CodeGroup>
