The Encryption module provides encryption and decryption functionality with support for multiple algorithms including ChaCha20-Poly1305, AES-256-GCM, AES-256-CBC, and AES-SIV.
Import
import { Encryption, EncryptionManager, Hmac, BaseDriver } from '@adonisjs/core/encryption'
import { defineConfig, drivers, errors } from '@adonisjs/core/encryption'
import type { EncryptionConfig } from '@adonisjs/core/types/encryption'
Overview
The Encryption module provides classes and utilities for encrypting and decrypting sensitive data. It supports purpose binding, multiple encryption keys, and various encryption algorithms.
Classes
Encryption
Main encryption class for encrypting and decrypting values.
Constructor
Methods
encrypt
Encrypts a string or object value.
Optional purpose for binding the encrypted value to a specific use case
const encryption = new Encryption({ key: 'secret-key' })
const encrypted = encryption.encrypt('sensitive data')
const encryptedWithPurpose = encryption.encrypt('api-key', 'api-authentication')
decrypt
Decrypts an encrypted value.
The encrypted string to decrypt
Optional purpose that must match the purpose used during encryption
const decrypted = encryption.decrypt(encrypted)
const decryptedWithPurpose = encryption.decrypt(encryptedWithPurpose, 'api-authentication')
EncryptionManager
Manager class for handling multiple encryption instances.
Constructor
Configuration objectThe default encryptor name
Map of encryptor configurations
Methods
use
Returns a specific encryption instance.
Optional encryptor name. If omitted, returns the default encryptor.
const manager = new EncryptionManager({
default: 'app',
list: {
app: {
driver: (key) => new AES256GCM({ key }),
keys: ['app-key']
}
}
})
const encryptor = manager.use('app')
const encrypted = encryptor.encrypt('data')
Hmac
HMAC (Hash-based Message Authentication Code) class for creating and verifying message authentication codes.
Constructor
The secret key for HMAC generation
Methods
generate
Generates an HMAC signature for a message.
const hmac = new Hmac('secret-key')
const signature = hmac.generate('message')
verify
Verifies an HMAC signature.
Returns true if the signature is valid
const isValid = hmac.verify('message', signature)
BaseDriver
Base class for implementing custom encryption drivers.
Extend this class to create custom encryption implementations that can be used with the EncryptionManager.
class CustomDriver extends BaseDriver {
encrypt(value: string) {
// Custom encryption logic
}
decrypt(payload: string) {
// Custom decryption logic
}
}
Functions
defineConfig
Defines the encryption configuration for the application.
The encryption configuration objectOptional default encryptor name
Map of encryptor names to their configurations or providers
return
ConfigProvider<ResolvedConfig>
A configuration provider that lazily resolves encryption drivers
import { defineConfig, drivers } from '@adonisjs/core/encryption'
import env from '@adonisjs/core/services/env'
const encryptionConfig = defineConfig({
default: 'app',
list: {
app: drivers.aes256gcm({
id: 'app',
keys: [env.get('APP_KEY')]
}),
backup: drivers.chacha20({
id: 'backup',
keys: [env.get('BACKUP_KEY')]
})
}
})
Drivers
The drivers object provides factory functions for creating encryption driver configurations.
drivers.chacha20
Creates a ChaCha20-Poly1305 encryption driver configuration.
ChaCha20-Poly1305 is a modern authenticated encryption algorithm that provides excellent performance on systems without AES hardware acceleration.
config
ChaCha20Poly1305DriverConfig
required
Unique identifier for this encryptor
Array of encryption keys (supports key rotation)
chacha20: drivers.chacha20({
id: 'app',
keys: [env.get('APP_KEY')]
})
drivers.aes256cbc
Creates an AES-256-CBC encryption driver configuration.
AES-256-CBC is widely supported but consider using AES-256-GCM for new applications as it provides authenticated encryption.
config
AES256CBCDriverConfig
required
Unique identifier for this encryptor
aes256cbc: drivers.aes256cbc({
id: 'legacy',
keys: [env.get('LEGACY_KEY')]
})
drivers.aes256gcm
Creates an AES-256-GCM encryption driver configuration.
AES-256-GCM is an authenticated encryption algorithm that provides both confidentiality and integrity. It offers excellent performance on systems with AES hardware acceleration.
config
AES256GCMDriverConfig
required
Unique identifier for this encryptor
aes256gcm: drivers.aes256gcm({
id: 'app',
keys: [env.get('APP_KEY')]
})
drivers.aessiv
Creates an AES-SIV encryption driver configuration.
config
AESSIVDriverConfig
required
Unique identifier for this encryptor
aessiv: drivers.aessiv({
id: 'app',
key: env.get('APP_KEY')
})
drivers.legacy
Creates a Legacy encryption driver configuration for compatibility with AdonisJS v6.
The Legacy driver maintains compatibility with the old AdonisJS v6 encryption format using AES-256-CBC with HMAC SHA-256. Use this when migrating from older versions.
config
LegacyDriverConfig
required
legacy: drivers.legacy({
keys: [env.get('APP_KEY')]
})
Errors
The errors object contains encryption-specific exceptions.
E_BLIND_INDEX_NOT_SUPPORTED
Raised when attempting to compute blind indexes using the legacy driver.
import { errors } from '@adonisjs/core/encryption'
try {
// Some operation
} catch (error) {
if (error instanceof errors.E_BLIND_INDEX_NOT_SUPPORTED) {
console.error('Blind indexes not supported')
}
}
Example Usage
Configuration
// config/encryption.ts
import { defineConfig, drivers } from '@adonisjs/core/encryption'
import env from '@adonisjs/core/services/env'
export default defineConfig({
default: 'app',
list: {
app: drivers.aes256gcm({
id: 'app',
keys: [env.get('APP_KEY')]
}),
api: drivers.chacha20({
id: 'api',
keys: [env.get('API_KEY')]
}),
legacy: drivers.legacy({
keys: [env.get('OLD_APP_KEY')]
})
}
})
Basic Usage
import encryption from '@adonisjs/core/services/encryption'
// Encrypt data
const encrypted = encryption.encrypt('sensitive data')
// Decrypt data
const decrypted = encryption.decrypt(encrypted)
// Encrypt with purpose binding
const apiToken = encryption.encrypt('api-token-value', 'api-authentication')
const decryptedToken = encryption.decrypt(apiToken, 'api-authentication')
// Use specific encryptor
const apiEncryption = encryption.use('api')
const encryptedData = apiEncryption.encrypt('data')
Encrypting User Data
import encryption from '@adonisjs/core/services/encryption'
import User from '#models/user'
class UserController {
async store({ request, response }: HttpContext) {
const data = request.only(['name', 'email', 'ssn'])
// Encrypt sensitive data
const encryptedSSN = encryption.encrypt(data.ssn, 'user-ssn')
const user = await User.create({
name: data.name,
email: data.email,
ssn: encryptedSSN
})
return response.json(user)
}
async show({ params, response }: HttpContext) {
const user = await User.findOrFail(params.id)
// Decrypt sensitive data
const decryptedSSN = encryption.decrypt(user.ssn, 'user-ssn')
return response.json({
...user.toJSON(),
ssn: decryptedSSN
})
}
}
HMAC Signatures
import { Hmac } from '@adonisjs/core/encryption'
import env from '@adonisjs/core/services/env'
const hmac = new Hmac(env.get('HMAC_KEY'))
// Generate signature
const message = 'Important message'
const signature = hmac.generate(message)
// Verify signature
const isValid = hmac.verify(message, signature)
if (isValid) {
console.log('Signature is valid')
}
// Use case: Sign API requests
class ApiClient {
private hmac = new Hmac(env.get('API_SECRET'))
async makeRequest(endpoint: string, data: any) {
const payload = JSON.stringify(data)
const signature = this.hmac.generate(payload)
return fetch(endpoint, {
method: 'POST',
headers: {
'X-Signature': signature,
'Content-Type': 'application/json'
},
body: payload
})
}
}
Key Rotation
// config/encryption.ts
export default defineConfig({
default: 'app',
list: {
app: drivers.aes256gcm({
id: 'app',
keys: [
env.get('NEW_APP_KEY'), // New key (first = used for encryption)
env.get('OLD_APP_KEY') // Old key (still able to decrypt)
]
})
}
})
// The first key is used for encryption
// All keys are tried for decryption (supports seamless key rotation)
Notes
- Always use environment variables for encryption keys
- Purpose binding adds an extra layer of security by binding encrypted data to a specific use case
- Key rotation is supported by providing multiple keys (first key encrypts, all keys can decrypt)
- AES-256-GCM is recommended for new applications
- Use the Legacy driver only when migrating from AdonisJS v6
- Encrypted values are URL-safe base64 encoded strings