yakeing/php_jwsign
yakeing/php_jwsign is a lightweight PHP library for creating and verifying JSON Web Signature (JWS) tokens. It provides straightforward APIs for signing payloads, validating signatures, and adding JWS-based authentication or data integrity checks to PHP applications.
Know what you are installing first. Despite the name, yakeing/php_jwsign is not a JWS (RFC 7515) implementation. It is a small OpenSSL wrapper for encrypting/decrypting strings and is described by its author only as "a class of data encryption and decryption." Do not drop it at a JWT verification boundary or expect token interoperability with firebase/php-jwt or any compliant JOSE library.
The package is archived (last release 2019-08-06, 0 dependents, 35 stars). It still installs, but nothing upstream is maintained. Treat it as you would a copy-pasted helper class: usable if the crypto primitives it wraps are what you need, but you own the security review.
Minimal setup:
composer.json against your app; a 2019 package will often cap below PHP 8.x. If Composer refuses, you will need --ignore-platform-reqs in a scratch project to test, which is a strong signal to stop.composer require yakeing/php_jwsignexamples/ directory before writing integration code. There is no Laravel documentation and the API surface is a handful of methods; the README is the only accurate reference for constructor arguments and return types.ext-openssl is enabled and that the class loads:$r = new ReflectionClass(\Yakeing\JwSign\JwSign::class); // adjust namespace from README
First use case worth wiring up: encrypting a small opaque payload before it leaves your trust boundary—an API credential stored for a third party, or a signed webhook body. That is the shape this class is built for. Anything involving long-lived, high-value secrets should go through Laravel's own Crypt facade or defuse/php-encryption instead, both of which are maintained and have authenticated-encryption defaults.
Bind it, do not new it. Because the object holds key material, register a singleton in a service provider so a single instance per request is reused and key loading happens once.
// app/Providers/JwSignServiceProvider.php
public function register(): void
{
$this->app->singleton(JwSign::class, function () {
$key = config('jwsign.private_key_path');
return new JwSign(file_get_contents(storage_path($key)));
});
}
Register manually in config/app.php under providers—there is no extra.laravel auto-discovery in a package of this vintage.
Keep keys in storage/, never in config/. Point the config file at a path under storage/app/keys/, resolve it with storage_path(), and add that directory to .gitignore. Ship a .env variable (JWSIGN_PRIVATE_KEY_PATH) so each environment gets its own key.
Wrap it in your own interface. You want the rest of the app coupled to App\Contracts\PayloadCipher, not to an archived vendor class. This is the single most valuable pattern here—it makes swapping to phpseclib or Crypt a one-file change later.
interface PayloadCipher {
public function seal(string $plaintext): string;
public function open(string $ciphertext): string;
}
Eloquent cast for encrypted columns. A custom cast keeps controllers clean and centralizes the format:
class SealedCast implements CastsAttributes
{
public function get($model, $key, $value, $attributes) {
return $value === null ? null : app(PayloadCipher::class)->open($value);
}
public function set($model, $key, $value, $attributes) {
return [$key => $value === null ? null : app(PayloadCipher::class)->seal($value)];
}
}
Size the backing column as TEXT, not VARCHAR(255)—RSA ciphertext plus base64 framing routinely blows past 255 bytes.
Webhook signing pattern. Resolve the cipher in a middleware, seal the JSON body, and send the ciphertext in a dedicated header. On the inbound side, verify before your controller sees the payload, and compare with hash_equals() if you add your own HMAC layer on top.
Testing. Bind a stub implementation of PayloadCipher in TestCase::setUp() for feature tests, and keep one small integration test that exercises the real class with a throwaway 2048-bit keypair generated in the test fixture. This keeps the crypto out of the 95% of tests that do not care about it.
php_jwsign speaks JOSE. It does not. Every consumer needs to know the wire format is bespoke—document it in your API spec so nobody tries to validate these blobs with a JWT library.vendor/.utf8mb4 column will corrupt silently.false and emits a warning rather than throwing. Wrap calls in an adapter that converts failure to an exception; otherwise a decrypt failure looks like an empty string in your logs.v1:<base64> so you can introduce a new keypair and decrypt old rows during a migration window. Without this, rotation is a data-loss event.Crypt facade (symmetric, authenticated, zero integration cost), phpseclib (maintained RSA/OpenSSL work), firebase/php-jwt or web-token/jwt-framework if you actually need standards-compliant signing. Pick this package only if something specific—an existing wire format, a partner's reference implementation—requires it.How can I help you explore Laravel packages today?