Automatically Encrypting Eloquent Model Attributes
Applications often store fields that deserve additional protection at rest. Laravel can encrypt selected Eloquent attributes before they are written to the database and decrypt them automatically when they are read.
For modern Laravel applications, the built-in encrypted cast is preferable to overriding Eloquent’s magic __get() and __set() methods. It integrates with the model casting system and avoids interfering with Eloquent internals.
Basic Implementation
Define encrypted attributes in the model’s casts:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Profile extends Model
{
protected function casts(): array
{
return [
'gender' => 'encrypted',
'email' => 'encrypted',
];
}
}Depending on your Laravel version and model style, you may also see casts declared with the $casts property:
protected $casts = [
'gender' => 'encrypted',
'email' => 'encrypted',
];How It Works
When you assign and save an encrypted attribute:
$profile->email = 'user@example.com';
$profile->save();Laravel encrypts the value before persisting it. When you later access the attribute:
echo $profile->email;Laravel decrypts it through the model cast and returns the plaintext value to application code.
The encryption uses Laravel’s configured application encryption key, so losing that key can make existing encrypted values unrecoverable.
Why Use Encrypted Casts?
- Integrated with Eloquent → no need to override magic model behavior.
- Declarative → the model clearly identifies which fields are encrypted.
- Automatic → normal attribute access transparently performs encryption and decryption.
- Supports additional encrypted cast types → Laravel also supports encrypted arrays, objects, and collections in versions that provide those casts.
Important Limitations
1. Encrypted Values Are Not Searchable Normally
Laravel’s encryption uses a randomized initialization vector, so encrypting the same plaintext more than once produces different ciphertext. A query such as:
Profile::where('email', 'user@example.com')->first();will not match an encrypted email column.
If the application must look up records by a sensitive value, one common design is to keep the encrypted value plus a separate deterministic keyed hash for lookup. For example, store a normalized email in encrypted form and a keyed HMAC in a separate indexed column. Do not use an unsalted plain hash for low-entropy personal data because attackers can guess likely values offline.
2. Database Column Size
Encrypted ciphertext is longer than the original plaintext. Laravel recommends using TEXT or a sufficiently large column type for encrypted attributes rather than assuming a short VARCHAR will always fit.
3. Key Management
The application encryption key is critical. Protect it through your deployment secret-management process, back it up securely, restrict access, and plan key rotation before it becomes necessary. Rotating a key requires a strategy for decrypting and re-encrypting existing records.
4. Encryption Does Not Replace Authorization
Application-layer encryption helps protect database contents, backups, and some classes of accidental exposure, but authorized application code can still decrypt the data. Continue to use authentication, authorization policies, least-privilege database access, audit logging where appropriate, and secure transport.
Migrating Existing Plaintext Data
If a column already contains plaintext, adding an encrypted cast does not magically convert existing rows. Plan a migration process that reads each legacy value and writes it back through the encrypted cast, ideally in controlled batches with backups and verification.
Do not silently catch every decryption error and return the raw database value: doing so can hide corrupt data or key problems and may accidentally expose ciphertext or legacy plaintext. Treat migration state explicitly instead.
Conclusion
Laravel’s encrypted Eloquent casts provide a clean way to protect selected attributes without custom magic getters and setters. Use them for data that does not need direct database filtering, choose appropriate column sizes, and treat key management and migration planning as part of the feature rather than afterthoughts.