clod986
clod986

Reputation: 2647

How to solve "The payload is invalid" in Laravel 8 when the payload suddenly becomes NULL

I keep getting this error when trying to decrypt a password previously encrypted:

The payload is invalid.

And this is the relevant stack trace:

#0 /home/improojf/public_html/vendor/laravel/framework/src/Illuminate/Encryption/Encrypter.php(136): Illuminate\Encryption\Encrypter->getJsonPayload(NULL)
#1 /home/improojf/public_html/vendor/laravel/framework/src/Illuminate/Encryption/Encrypter.php(164): Illuminate\Encryption\Encrypter->decrypt('eyJpdiI6InloT0U...', false)
#2 /home/improojf/public_html/vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php(261): Illuminate\Encryption\Encrypter->decryptString('eyJpdiI6InloT0U...')
#3 /home/improojf/public_html/app/Models/Server.php(29): Illuminate\Support\Facades\Facade::__callStatic('decryptString', Array)
#4 /home/improojf/public_html/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php(473): Server->getPasswordAttribute('eyJpdiI6InloT0U...')

The biggest issue here is that a string randomly becomes NULL in the encrypter code, which makes no sense to me.

Another issue with this, is that some records just behave ad intended.

What do I use it for This is used to store passwords for smtp/pop3 servers on a database

What I tried This problem is perfectly solved by not encrypting/decrypting the password, which messes up the purpose

Does it always return error? No, in fact there are some records that behave normally

What are my guesses php artisan cache:clear might be an option as reported elsewhere, but I think there should be another solution. So far I have (untested) the following accessor while previously I only had the second try/catch

public function getPasswordAttribute($value){
    try {
        return Crypt::decryptString($value);
    } catch (\Illuminate\Contracts\Encryption\DecryptException $e) {
        \Illuminate\Support\Facades\Artisan::call('cache:clear');
    }
    try {
        return Crypt::decryptString($value);
    } catch (\Illuminate\Contracts\Encryption\DecryptException $e) {
        if(app()->runningUnitTests())
            return $value;
        else
            throw $e;
       }
}

Upvotes: 4

Views: 29748

Answers (3)

Luca Pisoni
Luca Pisoni

Reputation: 465

in my case the problem wasn't the column type, but the default $attributes value, because the value casting in my project it had to be of type 'encripted:collection'

/**
 * The model's default values for attributes.
 *
 * @var array
 */

protected $attributes = array(
    'is_complete' => false,
    'responses' => [], //Problem was here
);

I have solved by removing 'responses' => [],and defining an accessor instead:

public function getResponsesAttribute($value)
{
    return $value ? $value : collect();
}

Upvotes: 0

Norman Huth
Norman Huth

Reputation: 568

Use nullable text or longtext column

Upvotes: 0

John Lobo
John Lobo

Reputation: 15319

As per official documentation

Laravel's encryption services provide a simple, convenient interface for encrypting and decrypting text via OpenSSL using AES-256 and AES-128 encryption.

All of Laravel's encrypted values are signed using a message authentication code (MAC) so that their underlying value can not be modified or tampered with once

Before using Laravel's encrypter, you must set the key configuration option in your config/app.php configuration file.

It means encryption decryption depends on app key value.If new app key generated then old encrypted value will not work with new app key

Ref:https://laravel.com/docs/8.x/encryption

Updated

The issue is encrypted value was stored partially in database table due to data type varchar(191).

So better to change data type varchar(191) to longtext or text

Upvotes: 12

Related Questions