🔑 Credentials Management
Credentials là lifeblood của automation - API keys, OAuth tokens, database passwords. Bài này covers best practices để manage và protect chúng.
Credentials in n8n
How n8n Stores Credentials:
Text
1CREDENTIAL STORAGE FLOW2───────────────────────3 4User Input Encryption Database5────────── ────────── ────────6API Key → AES-256-GCM → Encrypted blob7Password → + N8N_KEY → in credentials_entity8Token → → 9 10Only decrypted when workflow runs!Credential Types:
Text
1COMMON CREDENTIAL TYPES2───────────────────────3 4API KEYS:5├── OpenAI API Key6├── Stripe API Key7├── SendGrid API Key8└── Generic Header Auth9 10OAUTH:11├── Google OAuth212├── Microsoft OAuth213├── Slack OAuth214└── Salesforce OAuth215 16DATABASE:17├── PostgreSQL18├── MySQL19├── MongoDB20└── Redis21 22BASIC AUTH:23├── HTTP Basic Auth24├── Custom Header25└── Query Parameter AuthCreating Credentials Securely
Best Practices:
Text
1✅ DO:2• Create credentials with minimal permissions3• Use service accounts, not personal4• Set expiration dates where possible5• Name credentials descriptively6• Document what each credential is for7 8❌ DON'T:9• Reuse credentials across environments10• Use admin/root credentials11• Share credentials via chat/email12• Store unencrypted anywhere13• Give more permissions than neededNaming Convention:
Text
1CREDENTIAL NAMING2─────────────────3 4Pattern: [Service]-[Environment]-[Purpose]5 6Examples:7• OpenAI-Prod-ChatGPT8• Stripe-Staging-Payments9• Slack-Prod-Notifications10• PostgreSQL-Prod-ReadOnly11• Google-Prod-SheetsSyncAPI Key Management
Creating Scoped API Keys:
OpenAI:
Text
11. Go to platform.openai.com22. Create new API key33. Name: "n8n-production"44. Set spending limits55. Copy immediately (shown once!)Stripe:
Text
11. Dashboard > Developers > API keys22. Create restricted key33. Permissions: 4 - Charges: Write5 - Customers: Read64. Name: "n8n-automation"SendGrid:
Text
11. Settings > API Keys22. Create API Key33. Permissions: Restricted Access4 - Mail Send: Full Access54. Name: "n8n-transactional"API Key Rotation:
Bash
1#!/bin/bash2# rotate-api-key.sh3 4SERVICE=$15OLD_KEY=$26NEW_KEY=$37 8echo "Rotating $SERVICE API key..."9 10# 1. Create new key in service dashboard11# 2. Update n8n credential12docker exec -it n8n sh -c "13 n8n credential:get --type=${SERVICE}14 # Update credential via API or manually15"16 17# 3. Test with new key18curl -H "Authorization: Bearer $NEW_KEY" https://api.example.com/test19 20# 4. Delete old key in service dashboard21 22echo "Rotation complete. Verify workflows!"OAuth Credentials
Setting Up OAuth:
Google OAuth2:
Text
11. Google Cloud Console22. Create OAuth 2.0 Client ID33. Type: Web Application44. Redirect URI: https://n8n.yourdomain.com/rest/oauth2-credential/callback55. Save Client ID and SecretMicrosoft OAuth2:
Text
11. Azure Portal > App registrations22. New registration33. Redirect URI: https://n8n.yourdomain.com/rest/oauth2-credential/callback44. Certificates & secrets > New client secret55. API permissions > Add required permissionsOAuth Security:
Text
1OAUTH BEST PRACTICES2────────────────────3 4✅ Use minimal scopes5 Google: Only gmail.readonly if only reading6 7✅ Review app permissions regularly8 Check for unused scopes9 10✅ Use organization accounts11 Not personal Gmail/Microsoft12 13✅ Set token expiration14 Refresh tokens when needed15 16✅ Monitor OAuth app activity17 Check for unauthorized accessDatabase Credentials
Creating Database Users:
SQL
1-- PostgreSQL: Create limited user for n8n2CREATE USER n8n_workflow WITH PASSWORD 'secure_password';34-- Grant only necessary permissions5GRANT CONNECT ON DATABASE production_db TO n8n_workflow;6GRANT USAGE ON SCHEMA public TO n8n_workflow;7GRANT SELECT ON ALL TABLES IN SCHEMA public TO n8n_workflow;8GRANT INSERT, UPDATE ON specific_table TO n8n_workflow;910-- Read-only user for reporting11CREATE USER n8n_readonly WITH PASSWORD 'another_password';12GRANT CONNECT ON DATABASE production_db TO n8n_readonly;13GRANT SELECT ON ALL TABLES IN SCHEMA public TO n8n_readonly;SQL
1-- MySQL: Create limited user2CREATE USER 'n8n_workflow'@'%' IDENTIFIED BY 'secure_password';3GRANT SELECT, INSERT, UPDATE ON production_db.* TO 'n8n_workflow'@'%';4FLUSH PRIVILEGES;Credential Sharing (Teams)
n8n Sharing Options:
Text
1CREDENTIAL ACCESS LEVELS2────────────────────────3 4PRIVATE (Default):5└── Only creator can use6 7SHARED WITH USERS:8├── Specific team members9└── Can use in their workflows10 11SHARED GLOBALLY:12├── All workspace users13└── Be careful with this!Setting Up Shared Credentials:
Text
11. Create credential22. Click Share button33. Add specific users44. Set permission level:5 - Use only (can't see values)6 - Full access (can edit)External Secret Management
Environment Variables:
yaml
1# docker-compose.yml2services:3 n8n:4 environment:5 # Reference from .env6 - OPENAI_API_KEY=${OPENAI_API_KEY}7 - STRIPE_API_KEY=${STRIPE_API_KEY}HashiCorp Vault Integration:
Bash
1# Fetch secrets at startup2#!/bin/bash3export OPENAI_API_KEY=$(vault kv get -field=key secret/n8n/openai)4export STRIPE_API_KEY=$(vault kv get -field=key secret/n8n/stripe)5 6docker compose up -dAWS Secrets Manager:
Bash
1# fetch-secrets.sh2#!/bin/bash3 4# Fetch from AWS Secrets Manager5export OPENAI_API_KEY=$(aws secretsmanager get-secret-value \6 --secret-id n8n/openai \7 --query SecretString \8 --output text | jq -r .api_key)9 10export DB_PASSWORD=$(aws secretsmanager get-secret-value \11 --secret-id n8n/database \12 --query SecretString \13 --output text | jq -r .password)Docker Secrets:
yaml
1# docker-compose.yml2version: "3.8"3 4services:5 n8n:6 image: n8nio/n8n7 secrets:8 - openai_key9 - stripe_key10 environment:11 # Read from file12 - OPENAI_API_KEY_FILE=/run/secrets/openai_key13 14secrets:15 openai_key:16 file: ./secrets/openai.txt17 stripe_key:18 file: ./secrets/stripe.txtBackup & Export Credentials
Export Encrypted (Safe):
Bash
1# Credentials stay encrypted with your key2docker exec n8n n8n export:credentials --all \3 --output=/backup/credentials.json4 5# Restore on same instance (same encryption key)6docker exec n8n n8n import:credentials \7 --input=/backup/credentials.jsonExport Decrypted (Careful!):
Bash
1# WARNING: Contains plain text secrets!2docker exec n8n n8n export:credentials --all --decrypted \3 --output=/backup/credentials-plain.json4 5# Encrypt the file immediately6gpg --symmetric --cipher-algo AES256 /backup/credentials-plain.json7 8# Secure delete original9shred -u /backup/credentials-plain.jsonCredential Audit
Audit Script:
Bash
1#!/bin/bash2# audit-credentials.sh3 4echo "=== N8N Credential Audit ==="5echo "Date: $(date)"6echo ""7 8# List all credentials9docker exec n8n n8n credential:list 2>/dev/null | while read line; do10 echo "$line"11done12 13# Check last used (requires custom query)14echo ""15echo "=== Usage Statistics ==="16docker exec n8n-postgres psql -U n8n -d n8n -c "17SELECT 18 c.name,19 c.type,20 COUNT(e.id) as usage_count,21 MAX(e.\"startedAt\") as last_used22FROM credentials_entity c23LEFT JOIN execution_entity e ON e.\"workflowData\"::text LIKE '%' || c.id || '%'24GROUP BY c.id, c.name, c.type25ORDER BY last_used DESC NULLS LAST;26"Cleanup Unused Credentials:
SQL
1-- Find credentials not used in any workflow2SELECT c.id, c.name, c.type3FROM credentials_entity c4WHERE c.id NOT IN (5 SELECT DISTINCT jsonb_array_elements(w.nodes)->>'credentials'->>'id'6 FROM workflow_entity w7);89-- Manual review before deletion!Credential Security Checklist
Text
1MONTHLY SECURITY REVIEW2───────────────────────3 4□ Review all credentials in n8n5□ Check for unused credentials → Remove6□ Verify permissions are minimal7□ Rotate keys older than 90 days8□ Update OAuth tokens if needed9□ Check for revoked/expired keys10□ Review shared credential access11□ Audit credential usage logs12□ Verify encryption key is backed up13□ Test credential backup/restoreTroubleshooting
"Credentials not found" Error:
Text
1Causes:21. Credential deleted32. Permission removed43. Wrong environment5 6Fix:71. Check credential exists82. Verify workflow has access93. Re-authenticate OAuth if expiredOAuth Token Expired:
Text
11. Go to credential settings22. Click "Reconnect"33. Re-authenticate44. Save credentialImport Failed:
Text
1Causes:21. Different encryption key32. Corrupt JSON file43. Version mismatch5 6Fix:71. Ensure same N8N_ENCRYPTION_KEY82. Validate JSON syntax93. Match n8n versionsBài Tập Thực Hành
Credentials Challenge
Implement secure credential management:
- Audit all existing credentials
- Create naming convention document
- Setup least-privilege database users
- Configure credential sharing policy
- Implement backup procedure
- Schedule monthly credential review
Secure your automation! 🔐
Key Takeaways
Remember
- 🔑 Least privilege - Only needed permissions
- 📝 Document - What each credential is for
- 🔄 Rotate regularly - 90 days max
- 💾 Backup encrypted - Never plain text
- 👥 Audit sharing - Who has access?
- 🧹 Clean up - Remove unused credentials
Tiếp Theo
Bài tiếp theo: User Management - Multi-user setup, invitations, và team organization.
