Skip to content

Plain Text

Store secrets as plain text (for default values only!).

Usage

Plain text is the default when no provider is specified:

toml
[secrets]
NODE_ENV = { default = "development" }  # ← Plain text, safe for non-sensitive defaults
LOG_LEVEL = { default = "info" }  # ← Plain text
API_TIMEOUT = { default = "30" }  # ← Plain text

When Plain Text is Appropriate

1. Non-Sensitive Defaults

toml
[secrets]
PORT = { default = "3000" }
HOST = { default = "localhost" }
NODE_ENV = { default = "development" }
LOG_LEVEL = { default = "info" }

2. Public Configuration

toml
[secrets]
PUBLIC_API_URL = { default = "https://api.example.com" }
CDN_URL = { default = "https://cdn.example.com" }

3. Development Fallbacks

toml
[secrets]
DATABASE_URL = { provider = "age", value = "encrypted-production-db...", default = "postgresql://localhost/dev_db" }  # ← Fallback for local dev

If the encrypted value can't be decrypted (e.g., missing key), falls back to the plaintext default.

❌ When NOT to Use Plain Text

Never for Passwords

toml
# ❌ BAD - Never do this!
[secrets]
DATABASE_PASSWORD = { default = "super-secret-password" }

# ✅ GOOD - Use encryption
[secrets]
DATABASE_PASSWORD = { provider = "age", value = "encrypted..." }

Never for API Keys

toml
# ❌ BAD
[secrets]
STRIPE_KEY = { default = "sk_live_abc123xyz789" }

# ✅ GOOD
[secrets]
STRIPE_KEY = { provider = "age", value = "encrypted..." }

Never for Tokens

toml
# ❌ BAD
[secrets]
JWT_SECRET = { default = "my-secret-key" }

# ✅ GOOD
[secrets]
JWT_SECRET = { provider = "age", value = "encrypted..." }

Mixing Plain and Encrypted

It's common to mix plain text defaults with encrypted values:

toml
[providers]
age = { type = "age", recipients = ["age1..."] }

[secrets]
DATABASE_PASSWORD = { provider = "age", value = "encrypted...", default = "dev-password" }  # Encrypted sensitive values, fallback for local dev
DATABASE_HOST = { default = "localhost" }  # Plain text non-sensitive defaults
DATABASE_PORT = { default = "5432" }
LOG_LEVEL = { default = "info" }

Security Best Practices

  1. Never commit sensitive data as plain text
  2. Use encryption for anything that shouldn't be public
  3. Use plain text only for truly non-sensitive defaults
  4. Review .gitignore - Ensure sensitive files aren't tracked
  5. Use fnox scan to detect secrets - Scans for accidentally committed secrets

Scan for Secrets

fnox can scan your codebase for accidentally committed secrets:

bash
# Scan for potential secrets
fnox scan

# Scan specific directory
fnox scan src/

# Scan and fix (interactive)
fnox scan --fix

Examples

Safe Plain Text Usage

toml
# Application settings (non-sensitive)
[secrets]
APP_NAME = { default = "My Application" }
APP_VERSION = { default = "1.0.0" }
ENVIRONMENT = { default = "development" }
DEBUG_MODE = { default = "true" }
TIMEOUT_MS = { default = "5000" }
PUBLIC_SITE_URL = { default = "https://example.com" }  # Public URLs
DOCS_URL = { default = "https://docs.example.com" }

Mixed Usage (Plain + Encrypted)

toml
[providers]
age = { type = "age", recipients = ["age1..."] }

[secrets]
# Sensitive (encrypted)
DATABASE_URL = { provider = "age", value = "encrypted-connection-string..." }
API_KEY = { provider = "age", value = "encrypted-key..." }

# Non-sensitive (plain)
DATABASE_POOL_SIZE = { default = "10" }
CACHE_TTL_SECONDS = { default = "3600" }
FEATURE_FLAG_NEW_UI = { default = "false" }

Remember

  • ✅ Plain text is fine for public, non-sensitive configuration
  • ✅ Use defaults for fallback values
  • ❌ Never use plain text for passwords, keys, or tokens
  • ✅ Use age or other providers for sensitive data
  • ✅ Run fnox scan to catch accidental secrets

Next Steps

Released under the MIT License.