### Install crypto-for-laravel via Composer Source: https://github.com/roundly-consulting/crypto-for-laravel/blob/main/README.md Run this command to install the package. Requires PHP 8.4 with ext-openssl, ext-hash, ext-mbstring, and ext-sodium for Ed25519, plus Laravel 12 or 13. ```bash composer require roundly-consulting/crypto-for-laravel ``` -------------------------------- ### Sign and verify a JWS token with ES256 Source: https://github.com/roundly-consulting/crypto-for-laravel/blob/main/README.md Generates or loads a P-256 EC key, signs a token with a kid header and claims, then verifies it. The algorithm is pinned to ES256 and never read from the token. Temporal claims are checked with a 30-second leeway, and the 'sub' claim is asserted as a string. ```php use RoundlyConsulting\Crypto\Facades\Crypto; use RoundlyConsulting\Crypto\Signature\Algorithm; $key = Crypto::keys()->ec()->fromStorageOrGenerate('local', 'keys/jwt.pem'); // P-256, created on first boot $token = Crypto::jws()->sign( ['kid' => 'k1'], ['sub' => 'alice', 'exp' => now()->addHour()->timestamp], Crypto::es($key), ); $claims = Crypto::jws()->verify($token, Crypto::es($key), Algorithm::ES256); $claims->assertTemporal(leeway: 30); // throws once expired $claims->string('sub'); // "alice" ``` -------------------------------- ### Verify webhook HMAC, encrypt with AES-256-GCM, and verify TOTP Source: https://github.com/roundly-consulting/crypto-for-laravel/blob/main/README.md Shows three independent operations: computing an HMAC-SHA256 signature for a webhook payload and comparing it in constant time, sealing and opening an AES-256-GCM encrypted value bound to associated data, and generating a base32 secret with a provisioning URI to verify a TOTP code. ```php $expected = 'sha256='.Crypto::hmac()->signHex($request->getContent(), $webhookSecret); Crypto::constantTimeEquals($expected, $request->header('X-Hub-Signature-256', '')); $dataKey = Crypto::randomBytes(32); $sealed = Crypto::aes256Gcm()->seal($dataKey, $iban, associatedData: 'invoices:42'); $iban = Crypto::aes256Gcm()->open($dataKey, $sealed, associatedData: 'invoices:42'); $secret = Crypto::randomSecret(); // base32, for an authenticator app Crypto::provisioningUri($secret, 'alice@example.com', 'Acme Inc'); Crypto::totp()->verify($secret, $code); // the matched time step, or false ```