In Laravel, what is APP_KEY, what does php artisan key:generate write, and what happens when the key is missing?
answer
- one secret behind encryption and signing
- config('app.key') from the env
- 32 random bytes for AES-256-CBC
- base64: prefix; --show and --force
- MissingAppKeyException
basics
~20 sAPP_KEY is the secret the Laravel encrypter, encrypted cookies and signed URLs use. key:generate writes a random key (32 bytes for the default cipher), base64-encoded behind a base64: prefix, into .env; with no key, resolving the encrypter throws MissingAppKeyException.
solid answer
~40 s`APP_KEY` feeds `config('app.key')`, and the `encrypter` singleton behind the `Crypt` facade and the `encrypt()`/`decrypt()` helpers uses it to encrypt values and sign them with a MAC; the cookie-encryption middleware and signed URLs depend on it too. `php artisan key:generate` asks `Encrypter::generateKey()` for a key sized to `app.cipher` (32 random bytes for the default `AES-256-CBC`) and rewrites the `APP_KEY=` line in `.env` as `base64:...`. `--show` prints a fresh key without touching the file, and when a key already exists the command asks for confirmation in production unless you pass `--force`. The skeleton's Composer scripts run it when a project is created. If the key is empty, the first code that resolves the encrypter throws `MissingAppKeyException` ("No application encryption key has been specified."). The key must be secret, identical on every server, and stable.
code
bash · 8 lines# local: write a fresh key into .env
php artisan key:generate
# production secret store: print a key, change nothing
php artisan key:generate --show
# replace an existing key in production without the prompt
php artisan key:generate --forcego deeper
Know that APP_KEY is a secret, that key:generate writes it into .env as base64:..., and that an empty key raises MissingAppKeyException.
Explain which services use the key (Crypt, cookie encryption, signed URLs), how the base64: prefix is decoded, and why the key length must match app.cipher.
Show how the key is handled in real deploys: minted once with --show, stored in a secret store, shared by every server and worker, never regenerated on deploy.
Frame the key as a single shared secret with a wide blast radius, and argue for how an organisation stores, audits and rotates it across environments.
## What APP_KEY is `APP_KEY` is an environment variable that `config/app.php` reads into the `app.key` configuration value. It is the **application key**: one random secret that several framework services share. The most visible consumer is the **encrypter**, the object registered in the service container under the name `encrypter` and exposed through the `Crypt` facade and the global `encrypt()` and `decrypt()` helpers. Every value it produces is encrypted with the key and, for the default cipher, also signed with a **message authentication code (MAC)** derived from the same key, so a modified value is rejected rather than decrypted. Other parts of Laravel lean on the same secret: - the cookie-encryption middleware encrypts every cookie, including the session cookie, with the encrypter; - signed URLs are signed with an HMAC keyed by `app.key`; - queued jobs that implement `ShouldBeEncrypted` are encrypted with the encrypter before they reach the queue. Password hashing is **not** on that list: the hashing drivers make their own salts and never read `app.key`. ## What key:generate does `php artisan key:generate` is the supported way to create the key. It: 1. reads `app.cipher` (hard-coded to `AES-256-CBC` in the skeleton's `config/app.php`); 2. calls `Encrypter::generateKey()`, which returns `random_bytes()` of the size that cipher needs; 3. base64-encodes the bytes and prefixes them with `base64:`; 4. rewrites the existing `APP_KEY=` line of `.env` with the new value and updates the running config. Two options change that flow: - `--show` prints a newly generated key and writes nothing, which is how you mint a key for a secret store or a server that does not use `.env`; - `--force` skips the confirmation prompt. The prompt appears only when a key is already set and the environment is `production`. The command only replaces a line that exists. If `.env` has no `APP_KEY=` line it reports that it cannot set the key, with a specific message when `APP_KEY` is already present as a real environment variable. The skeleton's `composer.json` runs `key:generate` in its post-create scripts, so a fresh project normally has a key already. ## Key format and length The encrypter checks the key length against the cipher and throws a `RuntimeException` ("Unsupported cipher or incorrect key length") when they do not match. | `app.cipher` | Raw key length | What `key:generate` writes | |---|---|---| | `AES-256-CBC` (default) | 32 bytes | `base64:` + 44 base64 characters | | `AES-256-GCM` | 32 bytes | same as above | | `AES-128-CBC` / `AES-128-GCM` | 16 bytes | `base64:` + 24 base64 characters | When the service provider reads the key, it strips the `base64:` prefix and decodes the rest. A value without the prefix is used as raw bytes, which is why the config comment talks about a 32-character string. ## When the key is missing The encrypter is a lazily built singleton. When something first resolves it with an empty `app.key`, `EncryptionServiceProvider` throws `Illuminate\Encryption\MissingAppKeyException` with the message "No application encryption key has been specified." In a web app that is usually the first request, because the cookie-encryption middleware needs the encrypter. Laravel never invents a temporary key; running without one is an error, not a degraded mode. ## Operating rules that follow - **Generate once per environment, then share it.** Every web server and queue worker in one environment must hold the same key, or a cookie set by one server fails to decrypt on the next. - **Keep it out of Git.** `.env.example` ships `APP_KEY=` empty on purpose. - **Do not rerun it casually in production.** A new key logs every user out and makes existing ciphertext unreadable unless the old key is listed in `APP_PREVIOUS_KEYS`. That is why the command asks for confirmation. - **Rotate deliberately.** Rotation has its own procedure: list the old key as a previous key, re-encrypt stored data, then retire the old key. ## Where the key lives in each environment On a developer machine the key sits in `.env`, which is gitignored, and each developer can have their own because local data is disposable. In shared environments the picture changes: - **staging and production each get one key**, minted once and stored in the hosting platform's secret settings or a secret manager; - the value reaches PHP as a real environment variable, so `config/app.php` picks it up through `env('APP_KEY')` exactly as it would from `.env`; - when the configuration is cached, the key is baked into the cached config file, so that file deserves the same protection as the secret itself; - a CI pipeline that copies `.env.example` gets an empty `APP_KEY=` line and must run `php artisan key:generate` before the tests, or the first request fails with `MissingAppKeyException`. An interviewer who asks "what is APP_KEY?" is usually checking two things: that you know it is a secret and not a random framework setting, and that you know regenerating it is a breaking change rather than a harmless reset.
- Why does key:generate fail on a server where APP_KEY is injected as a real environment variable rather than kept in .env?The command only rewrites an existing `APP_KEY=` line in `.env`. With no such line it reports that it cannot set the key, naming the case where `APP_KEY` is already in the environment. On such servers you run `php artisan key:generate --show` once and store the printed value in the platform's secret store.
- Does changing APP_KEY invalidate the passwords stored with Hash::make()?No. The hashing drivers salt each hash themselves and never read `app.key`, so password hashes survive a key change. What breaks is everything encrypted or signed with the key: session and other cookies, values stored through `Crypt`, encrypted queued jobs, and previously issued signed URLs.
saying these in an interview costs you the question
- APP_KEY is the salt Laravel uses when hashing passwords.
- Each server should run key:generate on deploy to get its own key.
- Laravel creates a temporary key at runtime when APP_KEY is empty.
- key:generate is harmless to rerun in production at any time.
- APP_KEY can be a string of any length; Laravel pads it.