Skip to main content
When E2EE is enabled on a license product, all API responses (both success and error) are encrypted with AES-256-GCM. Your software decrypts the response locally using a shared encryption key.

Why Use E2EE

Without encryption, an attacker can intercept or modify the API response before it reaches your software. Common attacks include:
  • Man-in-the-middle — intercepting and tampering with the response in transit
  • Local proxy spoofing — setting up a fake local server that always returns "success": true
  • Response sniffing — reading license details, plan info, or activation data
E2EE prevents all three. Even if the response is intercepted, it cannot be read or modified without the encryption key.

Setup

1

Enable E2EE

Edit your license product in the dashboard and toggle E2EE on.
2

Copy the encryption key

After saving, copy the encryption key — a 64-character hex string (representing 32 bytes).
3

Embed the key in your software

Store the key in your application. Your code will use it to decrypt every API response.

Encrypted Response Format

When E2EE is enabled, the API always responds with this structure (regardless of success or error):
{
  "encrypted": true,
  "payload": "base64-encoded-ciphertext",
  "nonce": "base64-encoded-12-byte-nonce",
  "tag": "base64-encoded-16-byte-auth-tag"
}
FieldDescription
encryptedAlways true when E2EE is active
payloadBase64-encoded AES-256-GCM ciphertext
nonceBase64-encoded 12-byte initialization vector
tagBase64-encoded 16-byte authentication tag

Decryption Steps

  1. Base64-decode payload, nonce, and tag
  2. Convert your 64-character hex key to 32 raw bytes
  3. Decrypt using AES-256-GCM with the key, nonce, and tag
  4. Parse the resulting plaintext as JSON — this is the same response you would get without E2EE

Decryption by Language

Uses the built-in crypto module. No dependencies needed.
const crypto = require("crypto");

function decryptResponse(body, hexKey) {
  const key = Buffer.from(hexKey, "hex");
  const nonce = Buffer.from(body.nonce, "base64");
  const tag = Buffer.from(body.tag, "base64");
  const ciphertext = Buffer.from(body.payload, "base64");

  const decipher = crypto.createDecipheriv("aes-256-gcm", key, nonce);
  decipher.setAuthTag(tag);

  let plaintext = decipher.update(ciphertext, null, "utf8");
  plaintext += decipher.final("utf8");

  return JSON.parse(plaintext);
}

Key Rotation

You can rotate the encryption key at any time from the product edit page in your dashboard. When you rotate:
  • A new 64-character hex key is generated
  • The old key stops working immediately
  • You must update the key in your software and push a new version to your users
After rotating the key, any running instances of your software using the old key will fail to decrypt responses. Plan key rotations alongside software updates.

Security Considerations

What E2EE protects against

  • Intercepting and modifying API responses in transit
  • Setting up a fake local server that always returns "success": true
  • Sniffing license details, plan info, or activation data from the network

What E2EE does not protect against

  • Reverse engineering your compiled binary to extract the encryption key or bypass the check entirely
  • Memory dumping at runtime to read decrypted responses
  • Patching your binary to skip the verification call

Recommendations

E2EE raises the bar significantly, but treat it as one layer in a defense-in-depth approach, not a silver bullet.
  • Obfuscate your code — make it harder to read and reverse engineer
  • Embed verification deep in your application logic, not in a single easily-patchable function
  • Use native compilation (not interpreted scripts) when possible
  • Combine license verification with other integrity checks
  • Don’t store the encryption key as a plain string — derive it at runtime from multiple values