@growy/strapi-plugin-encrypted-field
v2.4.4
Published
Custom encrypted text field plugin for Strapi using AES-256-GCM
Downloads
996
Maintainers
Readme
Strapi Plugin - Encrypted Field
Official Growy AI plugin for Strapi that provides a custom encrypted text field using AES-256-GCM. Protect sensitive information directly in your database with transparent encryption and robust validation.
- ✅ Custom field "Encrypted Text" in the Content-Type Builder
- ✅ Automatic encryption AES-256-GCM on save
- ✅ Transparent decryption on read (admin panel and API)
- ✅ Backend validation with regex and length constraint support
- ✅ Admin UI with show/hide toggle, resizable inputs and copy to clipboard
- ✅ Copy notifications with confirmation toast when copying values
- ✅ Multi-language support (i18n): English and Spanish in the admin panel
- ✅ Robust key management with validation and clear error messages
- ✅ Encrypted data in database with unique IV and Auth Tag per operation
- ✅ Reusable in any collection or component
- ✅ Full support for nested components and complex structures
Requirements
- Strapi: v5.0.0 or higher
- Node.js: 18.x - 23.x
- npm: 6.0.0 or higher
Installation
npm install @growy/strapi-plugin-encrypted-field
# or
yarn add @growy/strapi-plugin-encrypted-fieldConfiguration
1. Enable the plugin
Create or edit config/plugins.js or config/plugins.ts:
module.exports = {
'encrypted-field': {
enabled: true,
},
};2. Configure the encryption key (REQUIRED)
Option A: Environment variable (recommended)
Add to your .env:
ENCRYPTION_KEY=your_64_character_hex_key_hereOption B: Configuration file
Use this option if you need to read the key from a different environment variable name or from a secrets provider:
module.exports = ({ env }) => ({
'encrypted-field': {
enabled: true,
config: {
encryptionKey: env('MY_CUSTOM_SECRET_KEY'),
},
},
});Generate a secure key
Run this command once to generate a valid key:
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"This outputs a 64-character hexadecimal key (32 bytes) ready to use.
⚠️ CRITICAL - Key Management:
- Store the key securely (secrets manager, encrypted environment variables)
- Never include it in version control
- If you lose the key, you will not be able to decrypt existing data
- Use the same key across all environments sharing the same database
- For production, consider services like AWS Secrets Manager, HashiCorp Vault or similar
3. Rebuild the admin panel (first install only)
After installing the plugin for the first time, rebuild the admin panel:
npm run build
npm run developUsage
1. Add an encrypted field to a collection
- Go to Content-Type Builder
- Select a collection or create a new one
- Click "Add another field"
- Search for "Encrypted Text" (with 🔒 icon)
- Set the field name
- Save and restart Strapi
2. Using the field in the admin panel
The field works like a regular text field with additional security features:
- Values are hidden by default (shown as
***) - Eye button: Toggles between show/hide the value
- Copy button: Copies the value to clipboard with a confirmation notification
- On save: Value is automatically encrypted before storing
- On read: Value is automatically decrypted before displaying
- In the DB: Stored as
iv:authTag:encryptedText(unreadable without the key) - In components: Works the same in nested components at any depth
3. API Usage
The API always returns decrypted values for authorized requests. You write plain text, the plugin handles encryption transparently.
# Create an entry with an encrypted field
curl -X POST http://localhost:1337/api/users \
-H "Content-Type: application/json" \
-d '{
"data": {
"name": "John",
"apiKey": "my-secret-key-123"
}
}'
# Read (automatically returns decrypted)
curl -X GET http://localhost:1337/api/users/1
# Response: { "name": "John", "apiKey": "my-secret-key-123" }Data Validation
The plugin supports validation before encryption. If validation fails, the value is rejected before being encrypted or saved.
Configure regex validation
- In Content-Type Builder, select the encrypted field
- Go to the "Advanced Settings" tab
- In "RegEx pattern", enter your regular expression
- Save the changes
Example: To only accept values that look like an API key:
^sk-[a-zA-Z0-9]{32}$Usage Example
"User" collection with an encrypted API Key
Schema:
{
"name": "string",
"email": "email",
"apiKey": "plugin::encrypted-field.encrypted-text"
}What gets stored in the DB:
apiKey: "a1b2c3d4e5f6....:f9e8d7c6b5a4....:9f8e7d6c5b4a3..."What the admin panel and API show:
apiKey: "sk-1234567890abcdef"Security & Architecture
Technical Specifications
- Algorithm: AES-256-GCM (NIST standard, military grade)
- Key size: 256 bits (32 bytes, 64 hex characters)
- IV (Initialization Vector): 96 bits (12 bytes) randomly generated per operation
- Auth Tag: 128 bits (16 bytes) for integrity verification
- Stored format:
iv:authTag:encryptedData(all in hexadecimal) - Key caching: Encryption key is parsed and cached in memory for optimal performance
Security Features
- ✅ Authenticated encryption: GCM provides both confidentiality and integrity
- ✅ Unique IV: Every encryption operation generates a random IV
- ✅ Tamper resistance: Auth Tag detects any modification to the ciphertext
- ✅ Input validation: Regex and custom constraints supported
- ✅ Safe error handling: Controlled logs without exposing sensitive data
- ✅ Double-layer decryption: Lifecycle hooks (internal) + middleware (API responses)
Best Practices
- Key rotation: Use the included rotation script when changing keys (see below)
- Environment separation: Use different keys per dev/staging/prod
- Auditing: Monitor encryption/decryption error logs
- Key backup: Keep secure copies of keys in multiple locations
- Private fields: Mark sensitive fields as "private" to exclude them from the public API
Key Rotation (Preventing Data Loss)
⚠️ IMPORTANT: If you change ENCRYPTION_KEY in your .env without re-encrypting your data first, all existing data will become permanently unreadable.
Follow this safe process to rotate your key:
- Keep your OLD key — do not remove it yet.
- Generate a NEW key (64-character hexadecimal).
- Export the encrypted values from your database.
- Run the rotation script included in this plugin:
The script reads encrypted values from stdin, decrypts with the old key, and re-encrypts with the new key, writing the results to stdout.# From your Strapi project root node node_modules/@growy/strapi-plugin-encrypted-field/scripts/rotate-key.js \ --old=<YOUR_CURRENT_64_CHAR_KEY> \ --new=<YOUR_NEW_64_CHAR_KEY> - Update your database with the new encrypted values output by the script.
- Update your
.envwith theNEW_KEYand remove the old one. - Restart Strapi.
Use Cases
- 🔑 Third-party API Keys
- 🔐 Access tokens
- 🔒 Webhook secrets
- 💳 Payment or sensitive information
- 📧 SMTP credentials
- 🔑 Application passwords
Known Limitations
- ❌ Search: Cannot search by encrypted fields (data is encrypted in DB)
- ❌ Sorting: Cannot sort by encrypted fields
- ❌ Filters: Cannot apply direct filters on encrypted fields
- ❌ Unique constraint: Strapi's unique validation will not work correctly on encrypted fields because each encryption produces different ciphertext (random IV)
- ⚠️ Performance: Encryption/decryption adds minimal overhead (~1-2ms per operation)
- ⚠️ Key synchronization: All environments sharing the same DB must use the same key
License
MIT © 2025 Growy AI
Developed by
Growy AI - AI and business automation solutions
Main author: Zahir El isaac
