NewWe open-sourced 50+ Laravel packages
Custom AI apps, agents and automation — Roundly ConsultingRoundly
All packages
Crypto for Laravel

Zero-config design

The package ships no config file, never calls env() and never resolves a key implicitly. Every secret, PEM and OTP secret is a #[\SensitiveParameter] argument, and every behavioural knob — hash algorithm, RSA bits, OTP digits and period — is a constructor default or a named argument. Your application owns configuration and wiring; the package owns the math and encoding.

The one explicit exception: *FromConfig

The opt-in *FromConfig key factories read a config key you name, at your call site — an accessor of your own config, never the package configuring itself. They are the only config() calls in the whole package, and an architecture test enforces it:

FactoryReads and validates
HmacSecret::fromConfig($key)An HMAC secret — the same strength guards as fromString().
RsaKey::publicFromConfig($key)An RSA public key PEM (2048–8192 bits).
RsaKey::privateFromConfig($key)An RSA private key PEM (2048–8192 bits).
EcKey::publicFromConfig($key)An EC public key PEM (P-256, P-384 or P-521).
EcKey::privateFromConfig($key)An EC private key PEM (P-256, P-384 or P-521).
OkpKey::ed25519FromConfig($key)A raw 32-byte Ed25519 public key.
OkpKey::secretKeyFromConfig($key)A raw 64-byte Ed25519 signing key (needs ext-sodium).

A missing, blank ('' or whitespace only, what a host’s KEY= gives) or non-string config value throws Signature\KeyLoadException::missingConfig() — never a PHP warning. Prefer these over reading config by hand, so key material is validated the moment it is loaded.

Wiring your own keyed provider

Because the package is zero-config, a keyed signer lives in your service provider, built from your config. The crypto package never sees where the key comes from:

use Illuminate\Support\ServiceProvider;
use RoundlyConsulting\Crypto\Signature\Hs;
use RoundlyConsulting\Crypto\Signature\Key\HmacSecret;

final class TokensServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        $this->app->singleton(Hs::class, fn () => new Hs(
            HmacSecret::fromString(config('tokens.secret')),
        ));
    }
}

Or lean on the opt-in loaders so the wiring reads straight from your config or a disk — and, for zero setup, bootstraps a secret on first boot:

$this->app->singleton(Hs::class, fn () => new Hs(
    HmacSecret::fromConfig('tokens.secret'),   // validated ≥ 32-byte secret
));

// self-bootstrapping variant — generates + persists the secret on first run:
$this->app->singleton(Hs::class, fn () => new Hs(
    HmacSecret::fromStorageOrGenerate('local', 'keys/tokens.key'),
));

The same pattern applies to Rs (RsaKey), Es (EcKey) and EdDSA (OkpKey). When a signer generates its own private key, persist the public half with publicPem() so a separate verifier can load it, then inject the bound signer wherever you sign or verify.

Show your open-source love

This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.

More ways to support, including crypto

By donating, you agree to our donation terms.

Want this built into your product?

We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.