Core Concepts
Install the Cipherion JavaScript SDK
Encryption
Cipherion provides two types of encryption methods: simple string encryption and deep encryption for complex data structures.
Simple Encryption
Use encrypt() to encrypt simple string values:
import { CipherionClient } from '@cipherion/client';
const client = new CipherionClient();
async function encryptString() {
const plaintext = "Hello, World!";
const encrypted = await client.encrypt(plaintext);
console.log(encrypted);
// Output: "encrypted_token,mapped_data,iv"
}Use Cases
- Encrypting passwords
- Encrypting API tokens
- Encrypting single field values
- Encrypting configuration secrets
Example: Password Encryption
async function encryptPassword(password: string) {
try {
const encrypted = await client.encrypt(password);
return {
success: true,
encryptedPassword: encrypted
};
} catch (error) {
console.error('Password encryption failed:', error);
throw error;
}
}
// Usage
const result = await encryptPassword("MySecurePass123!");Deep Encryption
Use deepEncrypt() to encrypt complex nested objects and arrays:
async function encryptObject() {
const userData = {
name: "John Doe",
email: "john@example.com",
address: {
street: "123 Main St",
city: "New York",
zipCode: "10001"
},
phones: ["+1234567890", "+0987654321"]
};
const result = await client.deepEncrypt(userData);
console.log('Encrypted:', result.encrypted);
console.log('Metadata:', result.meta);
}Response Structure
interface DeepEncryptResponse {
encrypted: any; // The encrypted data structure
meta: {
encryptionMetadata: {
excluded_fields: string[];
excluded_patterns: string[];
operation: "deep_encrypt";
};
totalFields: number; // Total fields in the object
billableFields: number; // Fields that were encrypted
totalPrice: number; // Cost of the operation
};
}Example with Metadata
const user = {
_id: "507f1f77bcf86cd799439011",
username: "johndoe",
email: "john@example.com",
ssn: "123-45-6789",
createdAt: "2024-01-15T10:30:00Z"
};
const result = await client.deepEncrypt(user, {
exclude_patterns: ["_id", "*At"]
});
console.log('Total fields:', result.meta.totalFields);
// Output: 5
console.log('Billable fields:', result.meta.billableFields);
// Output: 3 (username, email, ssn)
console.log('Cost:', result.meta.totalPrice);
// Output: 0.003
console.log('Encrypted data:', result.encrypted);
// {
// _id: "507f1f77bcf86cd799439011", // Not encrypted
// username: "encrypted_...",
// email: "encrypted_...",
// ssn: "encrypted_...",
// createdAt: "2024-01-15T10:30:00Z" // Not encrypted
// }Nested Objects
Deep encryption handles nested structures automatically:
const company = {
name: "Acme Corp",
employees: [
{
id: 1,
name: "Alice",
salary: 100000,
address: {
street: "456 Oak Ave",
city: "Boston"
}
},
{
id: 2,
name: "Bob",
salary: 95000,
address: {
street: "789 Pine Rd",
city: "Seattle"
}
}
]
};
const result = await client.deepEncrypt(company, {
exclude_fields: ["employees[*].id"] // Keep IDs unencrypted
});
console.log(result.encrypted);
// All fields encrypted except employee IDsArrays
Arrays are encrypted element by element:
const data = {
users: ["Alice", "Bob", "Charlie"],
scores: [95, 87, 92]
};
const result = await client.deepEncrypt(data);
console.log(result.encrypted);
// {
// users: ["encrypted_Alice", "encrypted_Bob", "encrypted_Charlie"],
// scores: ["encrypted_95", "encrypted_87", "encrypted_92"]
// }Selective Array Encryption
Encrypt specific array elements:
const data = {
users: ["Alice", "Bob", "Charlie", "Diana"]
};
const result = await client.deepEncrypt(data, {
exclude_fields: ["users[1]", "users[3]"] // Don't encrypt Bob and Diana
});
console.log(result.encrypted);
// {
// users: [
// "encrypted_Alice",
// "Bob", // Not encrypted
// "encrypted_Charlie",
// "Diana" // Not encrypted
// ]
// }Performance Considerations
Field Count
The number of fields affects:
- Processing time
- API cost (billable fields)
- Response size
// Example: Large object
const largeObject = {
field1: "value1",
field2: "value2",
// ... 1000 more fields
};
const result = await client.deepEncrypt(largeObject);
console.log(`Encrypted ${result.meta.billableFields} fields`);
console.log(`Cost: $${result.meta.totalPrice.toFixed(4)}`);Optimization Tips
- Exclude unnecessary fields
const result = await client.deepEncrypt(data, {
exclude_patterns: ["_id", "__v", "*_at", "metadata"]
});- Use batch operations for multiple items
// Instead of loop
for (const item of items) {
await client.deepEncrypt(item); // ❌ Slow
}
// Use migration
await client.migrateEncrypt(items); // ✅ Fast- Cache encrypted data when possible
const cache = new Map();
async function getCachedEncryption(key: string, data: any) {
if (cache.has(key)) {
return cache.get(key);
}
const encrypted = await client.deepEncrypt(data);
cache.set(key, encrypted);
return encrypted;
}Data Types
Cipherion handles various data types:
const mixed = {
string: "Hello",
number: 42,
boolean: true,
null: null,
undefined: undefined,
date: new Date(),
array: [1, 2, 3],
object: { nested: "value" }
};
const result = await client.deepEncrypt(mixed);
// All types are preserved after encryption/decryptionnull and undefined values are preserved and not encrypted.
Encryption Best Practices
1. Always Use HTTPS
const client = new CipherionClient({
baseUrl: 'https://api.cipherion.in', // ✅ HTTPS
// NOT http://api.cipherion.in // ❌ Insecure
});2. Validate Data Before Encryption
function validateUserData(data: any) {
if (!data.email || !data.name) {
throw new Error('Missing required fields');
}
return true;
}
async function encryptUser(user: any) {
validateUserData(user);
return await client.deepEncrypt(user);
}3. Handle Errors Gracefully
import { CipherionError } from '@cipherion/client';
async function safeEncryption(data: any) {
try {
return await client.deepEncrypt(data);
} catch (error) {
if (error instanceof CipherionError) {
if (error.isRetryable()) {
// Retry logic
await delay(2000);
return await client.deepEncrypt(data);
}
console.error('Encryption failed:', error.getUserMessage());
}
throw error;
}
}4. Don't Encrypt Everything
// ❌ Bad: Encrypting IDs and metadata
const result = await client.deepEncrypt(data);
// ✅ Good: Exclude non-sensitive fields
const result = await client.deepEncrypt(data, {
exclude_fields: ["id", "userId"],
exclude_patterns: ["_id", "*_at", "version"]
});Decryption
Decrypt data that was encrypted using Cipherion's encryption methods.
Simple Decryption
Use decrypt() to decrypt strings encrypted with encrypt():
import { CipherionClient } from '@cipherion/client';
const client = new CipherionClient();
async function decryptString() {
const encrypted = "encrypted_token,mapped_data,iv";
const decrypted = await client.decrypt(encrypted);
console.log(decrypted);
// Output: "Hello, World!"
}Example: Password Verification
async function verifyPassword(
inputPassword: string,
encryptedPassword: string
): Promise<boolean> {
try {
const decrypted = await client.decrypt(encryptedPassword);
return inputPassword === decrypted;
} catch (error) {
console.error('Password verification failed:', error);
return false;
}
}
// Usage
const isValid = await verifyPassword(
"UserInputPass123",
"encrypted_stored_password"
);Deep Decryption
Use deepDecrypt() to decrypt complex objects:
async function decryptObject() {
const encrypted = {
name: "encrypted_token...",
email: "encrypted_token...",
address: {
street: "encrypted_token...",
city: "encrypted_token..."
}
};
const result = await client.deepDecrypt(encrypted);
console.log('Decrypted:', result.data);
}Response Structure
interface DeepDecryptResponse {
data: any; // The decrypted data structure
meta: {
decryptionMetadata: {
excluded_fields: string[];
excluded_patterns: string[];
failed_fields: string[]; // Fields that failed to decrypt
operation: "deep_decrypt";
};
};
}Important: Use Same Exclusions
Always use the same exclude_fields and exclude_patterns during decryption that were used during encryption.
// Encryption
const encrypted = await client.deepEncrypt(data, {
exclude_fields: ["id"],
exclude_patterns: ["_id", "*_at"]
});
// Decryption - MUST use same options
const decrypted = await client.deepDecrypt(encrypted.encrypted, {
exclude_fields: ["id"],
exclude_patterns: ["_id", "*_at"]
});Why This Matters
// ❌ Wrong: Different exclusions
const encrypted = await client.deepEncrypt(data, {
exclude_patterns: ["_id"]
});
const decrypted = await client.deepDecrypt(encrypted.encrypted, {
exclude_patterns: ["*_id"] // Different pattern!
});
// Result: May attempt to decrypt unencrypted fields
// ✅ Correct: Same exclusions
const encrypted = await client.deepEncrypt(data, {
exclude_patterns: ["_id"]
});
const decrypted = await client.deepDecrypt(encrypted.encrypted, {
exclude_patterns: ["_id"] // Same pattern
});Graceful Failure Handling
Handle corrupted or invalid encrypted data gracefully:
const encrypted = {
_id: "123",
name: "encrypted_valid_token",
email: "corrupted_data", // Corrupted!
phone: "encrypted_valid_token"
};
const result = await client.deepDecrypt(encrypted, {
exclude_patterns: ["_id"],
fail_gracefully: true // Don't throw on failure
});
console.log('Decrypted data:', result.data);
// {
// _id: "123",
// name: "John Doe",
// email: "corrupted_data", // Kept as-is
// phone: "+1234567890"
// }
console.log('Failed fields:', result.meta.decryptionMetadata.failed_fields);
// ["email"]When to Use Graceful Failure
- Production environments - Don't break the application
- Data migrations - Some records might be corrupted
- Partial data recovery - Get what you can
- Logging and monitoring - Track decryption issues
Without Graceful Failure
try {
const result = await client.deepDecrypt(encrypted, {
fail_gracefully: false // Throw on first failure (default)
});
} catch (error) {
console.error('Decryption failed:', error);
// Entire operation fails on first corrupted field
}Handling Failed Fields
async function decryptWithRecovery(encrypted: any) {
const result = await client.deepDecrypt(encrypted, {
exclude_patterns: ["_id", "*_at"],
fail_gracefully: true
});
// Check for failures
const failedFields = result.meta.decryptionMetadata.failed_fields;
if (failedFields.length > 0) {
console.warn(`Failed to decrypt ${failedFields.length} fields:`, failedFields);
// Log for monitoring
await logDecryptionFailure({
recordId: result.data._id,
failedFields: failedFields,
timestamp: new Date()
});
// Optionally alert admins
if (failedFields.includes('ssn') || failedFields.includes('payment')) {
await alertAdmin('Critical field decryption failed', result.data._id);
}
}
return result.data;
}Nested Objects Decryption
const encrypted = {
user: {
profile: {
name: "encrypted_...",
email: "encrypted_..."
},
settings: {
theme: "encrypted_...",
notifications: "encrypted_..."
}
}
};
const result = await client.deepDecrypt(encrypted);
console.log(result.data);
// Fully decrypted nested structureArray Decryption
const encrypted = {
users: [
"encrypted_Alice",
"encrypted_Bob",
"encrypted_Charlie"
],
scores: [
"encrypted_95",
"encrypted_87",
"encrypted_92"
]
};
const result = await client.deepDecrypt(encrypted);
console.log(result.data);
// {
// users: ["Alice", "Bob", "Charlie"],
// scores: [95, 87, 92]
// }Selective Array Decryption
// If you excluded specific array elements during encryption
const encrypted = {
users: [
"encrypted_Alice",
"Bob", // Was excluded during encryption
"encrypted_Charlie",
"Diana" // Was excluded during encryption
]
};
const result = await client.deepDecrypt(encrypted, {
exclude_fields: ["users[1]", "users[3]"] // Same exclusions
});
console.log(result.data.users);
// ["Alice", "Bob", "Charlie", "Diana"]Storing Decryption Options
Store encryption options with your data for consistent decryption:
// During encryption
const encryptionOptions = {
exclude_fields: ["id", "userId"],
exclude_patterns: ["_id", "*_at"]
};
const encrypted = await client.deepEncrypt(data, encryptionOptions);
// Store both
await database.save({
data: encrypted.encrypted,
_encryptionOptions: encryptionOptions, // Store options
_encrypted: true
});
// During decryption
const record = await database.findById(id);
const decrypted = await client.deepDecrypt(
record.data,
record._encryptionOptions // Use stored options
);Performance Optimization
1. Cache Decrypted Data
import LRU from 'lru-cache';
const decryptionCache = new LRU({
max: 500,
ttl: 1000 * 60 * 5 // 5 minutes
});
async function cachedDecrypt(encrypted: any, cacheKey: string) {
const cached = decryptionCache.get(cacheKey);
if (cached) return cached;
const result = await client.deepDecrypt(encrypted, {
exclude_patterns: ["_id"],
fail_gracefully: true
});
decryptionCache.set(cacheKey, result.data);
return result.data;
}2. Parallel Decryption
async function decryptMultiple(encryptedArray: any[]) {
const results = await Promise.all(
encryptedArray.map(item =>
client.deepDecrypt(item, {
exclude_patterns: ["_id"],
fail_gracefully: true
})
)
);
return results.map(r => r.data);
}3. Lazy Decryption
Only decrypt fields when needed:
class LazyDecryptedUser {
private _decrypted: any = null;
constructor(private encrypted: any) {}
async getName() {
if (!this._decrypted) {
await this.decrypt();
}
return this._decrypted.name;
}
async getEmail() {
if (!this._decrypted) {
await this.decrypt();
}
return this._decrypted.email;
}
private async decrypt() {
const result = await client.deepDecrypt(this.encrypted);
this._decrypted = result.data;
}
}Error Handling
import { CipherionError } from '@cipherion/client';
async function safeDecryption(encrypted: any) {
try {
return await client.deepDecrypt(encrypted, {
fail_gracefully: false
});
} catch (error) {
if (error instanceof CipherionError) {
switch (error.statusCode) {
case 400:
console.error('Invalid encrypted data format');
break;
case 401:
console.error('Invalid credentials');
break;
case 500:
console.error('Server error during decryption');
if (error.isRetryable()) {
// Retry logic
await delay(2000);
return await client.deepDecrypt(encrypted, {
fail_gracefully: false
});
}
break;
default:
console.error('Decryption error:', error.getUserMessage());
}
}
throw error;
}
}Common Pitfalls
1. Mismatched Exclusions
// ❌ Wrong
const encrypted = await client.deepEncrypt(data, {
exclude_patterns: ["_id", "*_at"]
});
const decrypted = await client.deepDecrypt(encrypted.encrypted, {
exclude_patterns: ["_id"] // Missing "*_at"
});
// ✅ Correct
const options = {
exclude_patterns: ["_id", "*_at"]
};
const encrypted = await client.deepEncrypt(data, options);
const decrypted = await client.deepDecrypt(encrypted.encrypted, options);2. Not Handling Failures
// ❌ Wrong - assumes all fields decrypt successfully
const result = await client.deepDecrypt(encrypted);
const email = result.data.email; // Might be corrupted!
// ✅ Correct - check for failures
const result = await client.deepDecrypt(encrypted, {
fail_gracefully: true
});
if (result.meta.decryptionMetadata.failed_fields.includes('email')) {
console.warn('Email field is corrupted');
// Handle appropriately
}3. Decrypting Unencrypted Data
// ❌ Wrong - no check
const decrypted = await client.deepDecrypt(data);
// ✅ Correct - verify encryption flag
if (data._encrypted === true) {
const decrypted = await client.deepDecrypt(data);
} else {
// Data is already in plaintext
return data;
}Best Practices
- Store encryption options with data
await database.save({
data: encrypted.encrypted,
_encryptionOptions: options
});- Use graceful failure in production
const result = await client.deepDecrypt(encrypted, {
fail_gracefully: process.env.NODE_ENV === 'production'
});- Monitor failed decryptions
if (result.meta.decryptionMetadata.failed_fields.length > 0) {
await metrics.increment('decryption_failures', {
fields: result.meta.decryptionMetadata.failed_fields
});
}- Clear decrypted data after use
let decrypted = await client.deepDecrypt(encrypted);
// Use the data
processData(decrypted.data);
// Clear from memory
decrypted = null;Field Exclusions
Field exclusions allow you to selectively encrypt data while keeping certain fields in plaintext. This is crucial for maintaining searchability, reducing costs, and preserving data structure.
Why Exclude Fields?
1. Maintain Searchability
Database queries require unencrypted fields:
// Keep user ID unencrypted for queries
await client.deepEncrypt(user, {
exclude_fields: ["userId"]
});
// Now you can query: db.users.find({ userId: "123" })2. Reduce Costs
Only encrypt sensitive data:
const result = await client.deepEncrypt(data, {
exclude_patterns: ["_id", "__v", "*_at"]
});
console.log(`Billable fields: ${result.meta.billableFields}`);
// Lower billable fields = lower costs3. Preserve Metadata
Keep system fields unencrypted:
await client.deepEncrypt(document, {
exclude_patterns: ["createdAt", "updatedAt", "version"]
});4. Improve Performance
Fewer encrypted fields = faster operations:
// Exclude non-sensitive fields
await client.deepEncrypt(data, {
exclude_patterns: ["_id", "metadata.*", "stats.*"]
});Exclusion Methods
1. Exact Path Matching (exclude_fields)
Specify exact paths to exclude:
const data = {
id: "user_123",
profile: {
name: "John Doe",
email: "john@example.com"
},
settings: {
theme: "dark",
language: "en"
}
};
await client.deepEncrypt(data, {
exclude_fields: [
"id", // Top-level field
"profile.email", // Nested field
"settings.theme" // Another nested field
]
});2. Pattern Matching (exclude_patterns)
Use patterns for flexible matching:
await client.deepEncrypt(data, {
exclude_patterns: [
"_id", // Matches any field named "_id"
"__v", // Matches any field named "__v"
"*_at", // Matches fields ending with "_at"
"timestamp*", // Matches fields starting with "timestamp"
"meta_*" // Matches fields starting with "meta_"
]
});Common Patterns
MongoDB Documents
const mongoOptions = {
exclude_patterns: ["_id", "__v", "*At"]
};
await client.deepEncrypt(document, mongoOptions);User Profiles
const userOptions = {
exclude_fields: ["id", "username", "role"],
exclude_patterns: ["*_at", "lastLogin"]
};E-commerce Orders
const orderOptions = {
exclude_fields: ["orderId", "customerId", "items[*].productId"],
exclude_patterns: ["_id", "*_at", "status", "total"]
};