stechstudio/laravel-env-security
Laravel Env Security lets you encrypt sensitive values in your .env file and decrypt them automatically at runtime, keeping API keys, database credentials, and other secrets out of plaintext. Includes Artisan commands to encrypt and decrypt environment files.
Install and publish
composer require stechstudio/laravel-env-security
php artisan vendor:publish --provider="STS\EnvSecurity\EnvSecurityServiceProvider"
This gives you config/env-security.php — that file is the first thing to read, since it controls the key source, cipher, and the plaintext/encrypted filenames.
Set a key (not in the repo). Put it in your shell profile, your CI secret store, or your server's environment as ENV_SECURITY_KEY (or supply it at runtime with --key=). This key is separate from APP_KEY — mixing them up is the most common first-run mistake.
First use case — commit an encrypted .env:
php artisan env:encrypt # writes the encrypted file (e.g. .env.encrypted)
git add .env.encrypted && git commit -m "Add encrypted env"
php artisan env:decrypt # restores .env from it on a fresh clone
Make sure .env stays in .gitignore and only the encrypted artefact is tracked. The workflow you're buying is: small team, no secrets manager, config lives in git but isn't readable.
Per-developer loop. Each dev keeps their own plaintext .env locally; the encrypted file is the shared source of truth. On clone: set ENV_SECURITY_KEY, run env:decrypt, run artisan migrate. Document this in the README next to the setup steps, because a failed decrypt looks like an app misconfiguration.
Deploy pipeline ordering. Decrypt before config:cache, or the cached config will be built from a stale/missing .env:
php artisan env:decrypt --key="$ENV_SECURITY_KEY"
php artisan config:cache
php artisan route:cache
Prefer --key="$SECRET" in CI over writing the key into a file on disk — but only if your CI masks it (see gotchas).
One encrypted file per environment. .env.encrypted on main, a separate stage/production file elsewhere (different filename via config, or per-branch). Keeping a single file that everyone decrypts means every dev holds production credentials locally — don't do that.
Pulling the key from a vault. Since the key is resolved through config, you can set it at boot in a service provider's register() (or a config override) to fetch from SSM/Secrets Manager/Vault instead of an env var. That keeps the artisan commands' ergonomics without hardcoding ENV_SECURITY_KEY on the box.
Key rotation. Re-encrypt with the new key, commit, roll the key out to CI and servers in the same window, then revoke the old one. Ciphertext diffs are whole-file rewrites, so expect a noisy commit — that's normal, not corruption.
^3.0; if you're on Laravel 10/11, stay on ^2.4 — 3.0 may have dropped those constraints. Nothing in your application code should need to change; treat it as a composer update + full test-suite run, and check the PHP minimum as well.--key="$SECRET" in a script run with -v, or an un-masked CI variable, leaks everything in one log line. Mask the secret and avoid echoing the command.env:decrypt overwrites .env. On a machine that already has a working local .env, this silently replaces it with the committed environment's values. Back up or use a separate checkout.core.autocrlf=true, decryption fails with a useless error. Add a .gitattributes entry forcing LF for the encrypted file.ENV_SECURITY_KEY, not APP_KEY, (b) the cipher in config matches what it was encrypted with, (c) the key encoding (raw vs. base64) hasn't changed between environments.config:cache must re-run; otherwise the app keeps booting with the old values and you'll debug the wrong layer.How can I help you explore Laravel packages today?