Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Encryption Laravel Package

marko/encryption

Encryption support for the Marko framework, providing a simple service-provider integration for encrypting and decrypting application data with configurable keys and ciphers, plus helpers for secure serialization of values across your app.

View on GitHub
Deep Wiki
Context7

Getting Started

marko/encryption is a contracts-only package: it ships the interfaces (and possibly a small exception class) that define how encryption is exposed throughout the Marko framework, but no concrete implementation. You rarely install it directly — it arrives transitively when you require the framework or the actual encrypter implementation (marko/encryption-implementation or equivalent).

  1. Install (usually implicit):
    composer require marko/encryption
    
  2. Look first at src/ — the entire surface is one or two interfaces (expect something like EncrypterInterface with encrypt() / decrypt()). Read those signatures before anything else; they are the contract you code against.
  3. First use case: type-hint the interface in a constructor and let the container resolve the concrete encrypter:
    use Marko\Encryption\Contracts\EncrypterInterface;
    
    final class ApiTokenVault
    {
        public function __construct(private readonly EncrypterInterface $encrypter) {}
    
        public function store(string $token): string
        {
            return $this->encrypter->encrypt($token);
        }
    }
    
    That is the whole day-to-day loop: depend on the contract, receive the implementation from the container, never reference a concrete class.

Implementation Patterns

Depend on the contract, not the class. Every consumer (services, jobs, listeners, console commands) should type-hint EncrypterInterface. This is the single most important pattern because the package has zero dependents — swapping implementations is expected, and hard-coding a class defeats the purpose.

Bind the implementation once. In your application service provider:

$this->app->bind(EncrypterInterface::class, function ($app) {
    return new OpenSslEncrypter($app['config']->get('encryption.key'));
});

Keep the key out of code — source it from config/env, and rotate it with a versioned keyring if the implementation supports it.

Encrypt at the boundary. Treat the encrypter as a persistence/transport edge concern. Encrypt in a repository or a dedicated EncryptedCast/value object, decrypt on read. Keep domain entities plain. Example pattern:

final class EncryptedString
{
    public function __construct(private string $ciphertext) {}

    public static function fromPlain(string $plain, EncrypterInterface $e): self
    {
        return new self($e->encrypt($plain));
    }

    public function reveal(EncrypterInterface $e): string
    {
        return $e->decrypt($this->ciphertext);
    }
}

Wrap for testability. Because it's an interface, write a trivial fake in tests:

final class PlaintextEncrypter implements EncrypterInterface
{
    public function encrypt(string $value): string { return $value; }
    public function decrypt(string $value): string { return $value; }
}

Bind it in the test container. You avoid managing real keys in unit tests and keep assertions readable.

Queue/job payloads. If you serialize encrypted values into queued jobs, decrypt inside the job handler, not at dispatch, so keys can rotate without invalidating in-flight jobs.

Migration workflow. Encrypting an existing column means: add a nullable ciphertext column, backfill via a command that pulls EncrypterInterface from the container, dual-read during rollout, then drop the plaintext column. Do the backfill in batched chunks — encryption is CPU-bound and per-row overhead is real.

Gotchas and Tips

  • It’s contracts only. If you composer require marko/encryption alone and try to instantiate something, you’ll get an interface you can’t new. You must also pull an implementation package (or write your own class satisfying the interface) and bind it. The absence of dependents confirms it’s a leaf contract, not a working encrypter.
  • Don’t fight the container. Resolve from the container everywhere, including in Artisan-style commands and middleware. new-ing a concrete encrypter means you skip key/config wiring and quietly break rotation.
  • Never encrypt what you must query. Ciphertext is non-deterministic under any sane implementation, so WHERE encrypted_col = ? won’t work. For searchable fields, store a separate deterministic hash/HMAC alongside the ciphertext, and document the trade-off.
  • Encoding pitfalls. Ciphertext is binary; store in TEXT/BLOB-appropriate columns, and base64-encode if you’re putting it in URLs, JSON, or headers. Decrypting a truncated or re-encoded value throws — treat decrypt() failures as data-integrity errors, not user-input errors.
  • Key management is your problem. This package won’t enforce key length, rotation, or storage. Keep the key in env/secret manager, never in git, and version ciphertexts (v1:...) so you can rotate later. Losing the key means unrecoverable data — back it up out-of-band.
  • Debugging decrypt failures. Log the ciphertext prefix/version and the exception class, never the plaintext or full key. Wrap decrypt() in a small try/catch that maps “invalid payload / bad MAC” to a domain error so callers can distinguish tampering from a missing key.
  • Version alignment. As a framework-split package, its interfaces track the Marko monorepo. Pin the framework and this package to compatible versions; a mismatched interface signature will surface as a fatal “class does not implement” error at container resolution, not at install time.
  • Extension points. If the package exposes an EncryptionServiceProvider or config (config/encryption.php), override the binding there rather than subclassing an implementation. If you need a custom cipher, implement the interface and rebind — that’s the intended extension seam, and it’s why the contract exists.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core