APP_KEY is a secret. Here's what it's used for & how you can rotate it

themsaid

Mohamed Said

Posted on January 26, 2020

APP_KEY is a secret. Here's what it's used for & how you can rotate it

People often think APP_KEY is used to hash passwords, it isn't. Here's what this key is used for:

  • Encrypting cookies.
  • Creating the signature for signed URLs and queued closures.
  • Encrypting values using the encrypt() and decrypt() helpers.

You should deal with the APP_KEY as a secret. If you think it has been exposed, you MUST change it. However, make sure you re-encrypt any stored encrypted values. Also understand that there'll be some side effects:

  • All previously queued closures won't be able to run.
  • All users will be logged out and all token values will be lost.
  • All previously created signed routes won't work.

You can override the encrypter in your app to use an old key if it failed to decrypt a value with the new key. That way you can keep your app running fully after rotation until all the values are re-encrypted.

<?php

namespace App\Providers;

use App\Encrypter;
use Illuminate\Support\Str;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        $this->app->singleton('encrypter', function($app){
            $config = $app->make('config')->get('app');

            if (Str::startsWith($key = $config['key'], 'base64:')) {
                $key = base64_decode(substr($key, 7));
            }

            return new Encrypter($key, $config['cipher']);
        });
    }
}
<?php

namespace App;

use Illuminate\Support\Str;

class Encrypter extends \Illuminate\Encryption\Encrypter
{
    /**
     * Decrypt the given value.
     *
     * @param  string  $payload
     * @param  bool  $unserialize
     * @return mixed
     *
     * @throws \Illuminate\Contracts\Encryption\DecryptException
     */
    public function decrypt($payload, $unserialize = true)
    {
        try{
            return parent::decrypt($payload, $unserialize);
        }catch(\Throwable $e){
            $currentKey = $this->key;

            $this->key = Str::startsWith(config('app.old_key'), 'base64:')
                            ? base64_decode(substr(config('app.old_key'), 7))
                            : config('app.old_key');

            return tap(parent::decrypt($payload, $unserialize), function () use ($currentKey) {
                $this->key = $currentKey;
            });
        }
    }
}
đź’– đź’Ş đź™… đźš©
themsaid
Mohamed Said

Posted on January 26, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related