This application implements secure encryption for storing sensitive access tokens (particularly Shopify access tokens) in the database.
- Encryption Algorithm: Uses Fernet symmetric encryption from the
cryptographylibrary - Key Derivation: PBKDF2-HMAC-SHA256 with 100,000 iterations
- Base64 Encoding: Encrypted tokens are base64 encoded for safe storage
Add the following to your .env file:
# Required - used for JWT and fallback encryption
SECRET_KEY=your-very-secure-secret-key-here
# Optional - dedicated encryption key (recommended for production)
ENCRYPTION_KEY=your-dedicated-encryption-key-for-tokensImportant:
- In production, use a strong, randomly generated
ENCRYPTION_KEY - If
ENCRYPTION_KEYis not set, the system will fall back to usingSECRET_KEY - Never commit these keys to version control
# The ShopifyService automatically handles encryption
shopify_service = ShopifyService()
# Encrypt token before storing
encrypted_token = shopify_service.encrypt_token(access_token)
# Decrypt token when needed for API calls
decrypted_token = shopify_service.decrypt_token(encrypted_token)
# Get decrypted token from database
decrypted_token = shopify_service.get_decrypted_token(db, shop_domain)from app.core.security import encrypt_token, decrypt_token
# Encrypt a token
encrypted = encrypt_token("shpat_1234567890abcdef...")
# Decrypt a token
original = decrypt_token(encrypted)# Use stored encrypted tokens for API calls
shop_info = await shopify_service.get_shop_info_with_stored_token(db, shop_domain)
# Generic API call with stored token
response = await shopify_service.make_api_call(
db=db,
shop_domain="myshop.myshopify.com",
endpoint="products.json",
method="GET"
)The access_token field in the shopify_stores table uses the Text type to accommodate encrypted tokens, which are longer than plain tokens:
- Plain token: ~38 characters
- Encrypted token: ~188 characters (base64 encoded)
For existing installations with plain text tokens:
- Backup your database first
- Create a migration script to encrypt existing tokens
- Test thoroughly in a staging environment
Example migration pseudocode:
# Migrate existing plain text tokens
for store in db.query(ShopifyStore).all():
if not is_encrypted(store.access_token): # Your validation logic
store.access_token = encrypt_token(store.access_token)
db.commit()- Data at Rest Protection: Tokens are encrypted in the database
- Key Rotation: Can implement key rotation by re-encrypting with new keys
- Breach Mitigation: Even if database is compromised, tokens are protected
- Compliance: Helps meet security standards for sensitive data storage
- Encryption overhead: Minimal impact on application performance
- Token length: Encrypted tokens are ~5x longer than plain text
- Memory usage: Slightly higher due to encryption operations
- Use a dedicated ENCRYPTION_KEY in production
- Rotate encryption keys periodically
- Monitor token usage and implement proper logging
- Regular security audits of encryption implementation
- Backup strategies should account for encrypted data
-
ImportError with cryptography: Install required dependencies
pip install cryptography
-
Key derivation errors: Ensure SECRET_KEY or ENCRYPTION_KEY is set
-
Decryption failures: Usually indicates:
- Wrong encryption key
- Corrupted encrypted data
- Token was not properly encrypted
The application logs encryption/decryption operations. Check logs for:
- Failed decryption attempts
- Key derivation issues
- Token validation errors