kduma/eloquent-encryptable
Transparently encrypt sensitive Eloquent attributes at rest. A simple trait encrypts chosen fields on save and decrypts them on read, so your code keeps using plain values while the database stores ciphertext—no schema changes required.
Architecture fit
The package targets the narrowest possible seam in a Laravel application: an Eloquent trait that intercepts attribute get/set and pipes values through an encryption layer before they hit the database column. That is architecturally unobtrusive — it does not touch the query builder, connection layer, or service container, so it composes with existing models without restructuring. For a TPM, the relevant question is not "does it fit" (it does) but "does it earn a dependency slot." Laravel ships a native encrypted cast that covers single-field symmetric encryption, which means this package's addressable scope is the delta above native casting: key rotation, deterministic/blind-index search, per-field key isolation, or multi-column envelopes. That delta is unverified here and must be confirmed against source before it justifies adoption.
Integration feasibility
Low technical effort, high governance effort. Integration is a trait import plus a $encryptable-style property per model; no migrations beyond widening columns (ciphertext is materially longer than plaintext — size columns for base64 overhead plus IV/tag, and for the possibility of future envelope metadata). The real cost is the decision to depend on an archived repository: adoption implies either accepting an unpatched dependency or taking on a fork. Given MIT licensing, the viable path is vendoring or maintaining an internal fork, which is a maintenance commitment, not an integration task.
Technical risk
WHERE, ORDER BY, LIKE, GROUP BY, or unique indexes server-side. Any existing query that filters on a to-be-encrypted field breaks or degrades to full-table hydration into PHP. Deterministic encryption restores equality lookups but leaks frequency patterns — a trade-off that must be an explicit, documented decision, not an implementation detail.APP_KEY rotation, re-encryption of existing rows, and dual-key read windows is where these packages typically fall short. Verify before anything else.Key questions
Crypt/Encrypter (inheriting the framework's key management and AES-256-GCM) or implement its own primitives?Stack fit Drop-in for any Laravel 8+ application using Eloquent. No infrastructure, queue, or storage changes required. It fits the "application-level field encryption" pattern, not the "database TDE / KMS envelope" pattern; if the compliance driver is a mandate for centralized key custody (KMS/HSM, per-tenant keys, audited decrypt calls), this package is the wrong layer and the effort should go to a KMS-backed custom cast instead.
Migration path Do not add it as a Packagist dependency. Import the source into the repo (or a private fork) behind an internal interface — a custom cast or our own trait that delegates — so the underlying library is a swappable implementation detail. Wrap the encryption call site in a single internal service (encrypt/decrypt/blind-index) and route all models through it. This keeps the door open to swap in a maintained library or native casts without touching model definitions.
Compatibility
Two concrete hazards: column width (ciphertext expansion, typically 1.4–2× plus overhead; plan TEXT for long fields) and existing data (a backfill plus dual-read window is required — read plaintext if decryption fails during transition, then re-encrypt). Coordinate with reporting/BI consumers: any downstream tool reading those columns directly will see ciphertext.
Sequencing
If steps 1–3 do not clear cleanly, fall back to native encrypted casts for at-rest needs and a maintained searchable-encryption package (e.g. CipherSweet-based) for blind-index requirements.
Maintenance The dominant cost. Archiving transfers all maintenance to us: Laravel major-version compatibility, PHP upgrades, and security patches. Budget a named owner and a periodic review cadence; treat it as internal code, not a dependency. This is the single line item that usually kills adoption at review.
Support None. No upstream maintainer, no issue triage, no release channel. Internal engineers must be capable of reading and debugging the encryption path. If the team cannot staff that, the package is disqualified regardless of code quality.
Scaling
Encrypted columns are effectively unindexable. Filtering, sorting, and LIKE searches on encrypted fields either move to application-side processing (row hydration into PHP — degrades nonlinearly with table size) or require deterministic encryption/blind indexes, which reintroduce pattern leakage and must be designed per query. Plan for a data-model split: keep searchable/joins-critical attributes in plaintext or blind-indexed form, encrypt only the fields that genuinely require it. Decryption adds per-row CPU on hydration; benchmark against realistic page sizes — usually acceptable, but it becomes visible on bulk exports and reporting jobs.
Failure modes
DB::table() updates, raw SQL, bulk inserts). Audit every write path to those columns.Ramp-up Engineer ramp-up on the API is hours — it is a trait. Operational ramp-up is the real cost: key management runbooks, rotation drills, restore-and-decrypt verification, and incident response for decryption failures. That is a multi-week enablement item owned by platform/security, not a sprint task.
Recommendation
Do not adopt as a live dependency. Treat it as reference source at best: extract the pattern into an owned custom cast over Laravel's Crypt, or adopt a maintained library if searchable encryption is required. Revisit only if an internal owner is funded and a security review of the vendored code clears.
How can I help you explore Laravel packages today?