This system provides secure, encrypted storage for payment gateway credentials and API keys in the database, replacing hardcoded .env values. All credentials are encrypted using AES-256-GCM encryption.
✅ Encrypted Storage: All sensitive credentials encrypted with AES-256-GCM
✅ Database Persistence: Credentials stored securely in database
✅ Web UI Management: SuperAdmin panel for easy credential management
✅ Audit Logging: Complete tracking of all credential changes
✅ Automatic Fallback: Falls back to .env if database unavailable
✅ Caching: 5-minute cache to reduce database queries
The master encryption key is used to encrypt/decrypt all credentials. Generate a secure 256-bit key:
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"Add this to your .env file:
MASTER_ENCRYPTION_KEY=<your_generated_key_here>Execute the SQL schema to create required tables:
# Connect to your MySQL database and run:
mysql -u your_user -p your_database < backend/database_updates/payment_api_keys_schema.sqlThis creates:
payment_api_keys- Stores encrypted credentialspayment_key_audit_logs- Tracks all changesencryption_metadata- Stores encryption algorithm info
Run the migration script to encrypt and move credentials from .env to database:
cd backend
node scripts/migrateEnvToDatabase.jsThis will:
- Read credentials from your
.envfile - Encrypt each credential using AES-256-GCM
- Store encrypted values in database
- Show migration summary
- Login to SuperAdmin panel:
http://localhost:5173/superadmin/login - Navigate to Payment Settings
- Verify all credentials are listed
- Test decryption by clicking Edit on any credential
To use database credentials instead of .env, update your code:
Before:
const razorpayKey = process.env.RAZORPAY_KEY_ID;After:
const apiKeyManager = require('./utils/apiKeyManager');
const razorpayKey = await apiKeyManager.getKey('RAZORPAY_KEY_ID');Or use helper methods:
const razorpayCredentials = await apiKeyManager.getRazorpayCredentials();
// Returns: { RAZORPAY_KEY_ID, RAZORPAY_KEY_SECRET, RAZORPAY_WEBHOOK_SECRET }All endpoints require SuperAdmin authentication.
GET /api/superadmin/payment-settings
GET /api/superadmin/payment-settings/:id/decrypt
PUT /api/superadmin/payment-settings/:id
Body: { key_value: "new_value", description: "..." }
POST /api/superadmin/payment-settings
Body: {
key_name: "NEW_API_KEY",
key_value: "value",
key_type: "razorpay|google_maps|aws|jwt|email",
is_sensitive: true,
description: "..."
}
DELETE /api/superadmin/payment-settings/:id
GET /api/superadmin/payment-settings/audit-logs/list
Query: ?page=1&limit=50&key_name=RAZORPAY&action=updated
- Algorithm: AES-256-GCM (Authenticated Encryption)
- IV: Random 16-byte IV for each encryption
- Auth Tag: 16-byte authentication tag prevents tampering
- Key Size: 256-bit master key
- Only SuperAdmin role can access payment settings
- All access logged with IP address and user agent
- JWT token required for all operations
- Every view, create, update, delete operation logged
- SHA256 hash of values stored for verification
- IP address and user agent tracked
- Cannot be deleted (only soft delete)
- Sensitive values masked in UI (••••••••)
- Passwords never logged in plaintext
- Database values encrypted at rest
- Automatic fallback to .env if decryption fails
const apiKeyManager = require('./utils/apiKeyManager');
// Get single key
const razorpayKey = await apiKeyManager.getKey('RAZORPAY_KEY_ID');
// Get multiple keys
const keys = await apiKeyManager.getKeys(['RAZORPAY_KEY_ID', 'RAZORPAY_KEY_SECRET']);
// Get all Razorpay credentials
const razorpay = await apiKeyManager.getRazorpayCredentials();
console.log(razorpay.RAZORPAY_KEY_ID);
console.log(razorpay.RAZORPAY_KEY_SECRET);
// Get AWS credentials
const aws = await apiKeyManager.getAWSCredentials();
// Get Email credentials
const email = await apiKeyManager.getEmailCredentials();
// Get JWT credentials
const jwt = await apiKeyManager.getJWTCredentials();
// Get Google Maps key
const mapsKey = await apiKeyManager.getGoogleMapsKey();// Clear specific key cache
apiKeyManager.clearCache('RAZORPAY_KEY_ID');
// Clear all cache
apiKeyManager.clearCache();
// Refresh all keys from database
await apiKeyManager.refreshCache();
// Disable cache for specific request
const key = await apiKeyManager.getKey('RAZORPAY_KEY_ID', false);The following credentials are automatically migrated:
JWT_SECRET- JWT signing secretJWT_EXPIRATION- Token expiration time
AWS_ACCESS_KEY_ID- AWS access keyAWS_SECRET_ACCESS_KEY- AWS secret keyAWS_REGION- AWS regionAWS_BUCKET_NAME- S3 bucket name
USER_GMAIL- SMTP email addressUSER_PASSWORD- SMTP password
RAZORPAY_KEY_ID- Razorpay API keyRAZORPAY_KEY_SECRET- Razorpay secretRAZORPAY_WEBHOOK_SECRET- Webhook signature secret
GOOGLE_MAPS_API_KEY- Maps API key
Problem: "MASTER_ENCRYPTION_KEY not found"
# Generate and add to .env:
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"Problem: "Key already exists in database"
- Keys are already migrated, skip or delete from database first
Problem: "Decryption failed"
- Check MASTER_ENCRYPTION_KEY matches the one used for encryption
- Ensure database values weren't manually modified
Problem: API key returns null
- Check if key exists in database:
SELECT * FROM payment_api_keys WHERE key_name = 'KEY_NAME' - Verify key is active:
is_active = TRUE - Check encryption key is correct
Problem: "Failed to decrypt data"
- MASTER_ENCRYPTION_KEY may have changed
- Database value may be corrupted
- Falls back to .env automatically
- Backup Before Migration: Always backup your database before running migration
- Keep .env Backup: Keep original .env file as backup until fully tested
- Rotate Keys Regularly: Update credentials periodically via SuperAdmin panel
- Monitor Audit Logs: Regularly check audit logs for unauthorized access
- Secure Master Key: Never commit MASTER_ENCRYPTION_KEY to version control
- Use Environment Variables: Keep MASTER_ENCRYPTION_KEY in .env, not in database
- Test After Migration: Verify all services work before removing .env values
backend/database_updates/payment_api_keys_schema.sql- Database schemabackend/routes/admin_management/paymentSettings.js- API routesbackend/utils/encryption.js- Encryption utilitybackend/utils/apiKeyManager.js- Key management utilitybackend/scripts/migrateEnvToDatabase.js- Migration script
frontend/src/app/services/paymentSettings.service.js- API servicefrontend/src/app/features/superadmin/PaymentSettings.jsx- UI component
- Updated
backend/server.js- Added payment settings route - Updated
frontend/src/App.jsx- Added payment settings page route - Updated
frontend/src/app/layouts/SuperAdminLayout.jsx- Added navigation link
For issues or questions:
- Check audit logs in SuperAdmin panel
- Review backend logs for encryption errors
- Verify MASTER_ENCRYPTION_KEY is set correctly
- Ensure database tables exist and have correct schema
- Master Encryption Key: This is the most critical secret. If compromised, all credentials are at risk.
- Database Access: Limit database access to authorized personnel only.
- Audit Logs: Regularly review audit logs for suspicious activity.
- Key Rotation: Implement a key rotation policy for production.
- Backup Security: Ensure database backups are also encrypted.
- Network Security: Use SSL/TLS for all database connections.
Before deploying to production:
- ✅ Generate strong MASTER_ENCRYPTION_KEY (64 hex characters)
- ✅ Run database migration on production database
- ✅ Migrate all credentials using migration script
- ✅ Test all services thoroughly
- ✅ Remove sensitive values from .env (keep MASTER_ENCRYPTION_KEY)
- ✅ Backup database with encrypted credentials
- ✅ Set up monitoring for audit logs
- ✅ Document key rotation procedures
This implementation follows industry-standard encryption practices and is designed for production use.