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

Jwt Key Mgmt Laravel Package

web-token/jwt-key-mgmt

PHP component for managing JSON Web Keys (JWK) and key sets (JWKSet): load, create, convert, and organize keys for JWT signing and encryption across symmetric and asymmetric algorithms. Part of the Web-Token JWT framework, with utilities for key set handling and selection.

Deep Wiki
Context7

Getting Started

Install (and pick the right package). The repo is marked READ ONLY — the component now ships inside the framework monorepo. On v3 use:

composer require web-token/jwt-framework

On v4/v5 use web-token/jwt-library instead. Only pull web-token/jwt-key-mgmt standalone if you are pinned to the v1/v2 split-package era. Requirements: PHP ext-openssl (and ext-sodium if you touch Ed25519/Ed448 / X25519 keys).

Where to look first — the entire surface you will use day-to-day is four classes under Jose\Component\KeyManagement:

Class Job
JWKFactory Turn PEM, secrets, certificates, files, or nothing into a JWK
JKUFactory Fetch a remote JWKS from a jku URL
X5UFactory Fetch a certificate from an x5u URL
Analyzer\* Lint keys for weak parameters

First realistic use case — you already have a PEM on disk and need a signing key for JWSBuilder:

use Jose\Component\KeyManagement\JWKFactory;

$privateKey = JWKFactory::createFromKeyFile(
    storage_path('keys/private.pem'),
    password: env('JWT_KEY_PASSPHRASE'), // null if unencrypted
    additionalValues: ['use' => 'sig', 'alg' => 'RS256', 'kid' => '2024-01']
);

That JWK is the same object you hand to JWSBuilder, JWTLoader, SignatureChecker, or persist as JSON. For HMAC, skip the file entirely:

$secret = JWKFactory::createFromSecret(config('app.jwt_secret'), ['use' => 'sig', 'alg' => 'HS256']);

Implementation Patterns

1. A key-loading layer, not scattered JWKFactory calls. Wrap creation in a single resolver service keyed by kid. This is the difference between a maintainable token layer and one that grows a new file_get_contents every sprint:

class KeyResolver
{
    public function forSigning(string $kid): JWK { /* cache + factory */ }
    public function forVerification(string $kid): JWKSet { /* may return set during rotation */ }
}

2. Persist keys as JSON, not as PEM blobs. JWK is JsonSerializable and round-trips through JWKFactory::createFromValues($array). Storing the JWK JSON (in a keys table, in config, in Vault) lets you carry kid, use, alg, and key_ops alongside the material — the metadata is what actually prevents algorithm-confusion bugs later.

3. Rotation via JWKSet, not key replacement. During a rollover, expose the old and new public keys in one set, sign with the new one, and drop the old after the max token lifetime + clock skew. JWKSet is what SignatureChecker consumes; the header kid selects among members.

4. Generation is an admin/CLI concern, never a request concern. JWKFactory::generateRSAKey(4096) and friends are deliberately verbose — run them in an artisan command or deployment step and store the result. Regenerating a key pair per request is the single most common performance footgun with this package.

// artisan jwt:key:generate
$jwk = JWKFactory::generateRSAKey(4096, ['use' => 'sig', 'alg' => 'RS256', 'kid' => Str::uuid()]);

For a public/private pair use createKeyPair() / createRSAKeyPair() and keep only the public half on verifiers.

5. Remote key sets: cache aggressively, validate defensively. JKUFactory makes a synchronous HTTP call through PSR-7/PSR-18. In Laravel, inject a caching wrapper (a few minutes TTL) around it, and never let a jku header decide where to fetch from in a multi-tenant context — allowlist the issuer's JKU URL yourself and pass it explicitly.

6. Analyze before you trust. The bundled analyzers catch weak RSA moduli, missing use, deprecated curves, and short HMAC secrets:

$analyzers = [new \Jose\Component\KeyManagement\Analyzer\AlgorithmAnalyzer(), /* ... */];
foreach ($analyzers as $analyzer) {
    $analyzer->analyze($jwk, $collection); // $collection accumulates messages
}

Run this once at boot/deploy and log the results — it turns silent misconfiguration into a startup failure.

7. Framework integration. Register the resolver as a singleton, bind it to your JWSBuilder, and expose the verifying JWKSet to whatever middleware validates tokens. The package is intentionally framework-agnostic; a Laravel service provider that publishes config/jwt.php and lazily resolves keys is the natural shape.

Gotchas and Tips

  • createFromKey vs createFromKeyFile. The former takes PEM content, the latter takes a path. Passing a path to createFromKey produces a confusing "unable to load key" from OpenSSL, not a file error.
  • Encrypted PEMs. Pass the passphrase as the second argument; an empty string is not the same as null. If you get a null JWK back, check openssl_error_string() — the factory swallows the detail.
  • Detection is heuristic. createFromKey tries to infer kty/alg from the material. Always set alg and use explicitly in additionalValues; relying on inference is how you end up signing with a key whose advertised algorithm doesn't match what you built the token with.
  • Symmetric keys must be oct. createFromSecret produces that, but a hand-built createFromValues(['kty' => 'oct', 'k' => base64_encode($s)]) requires the base64url of the raw bytes — a very common off-by-encoding bug.
  • kid is not generated for you. If you use a JWKSet with more than one key, always set kid yourself and put the same value in the JWS header.
  • JKU/X5U factories do live HTTP. No retries, no cache, no timeout tuning out of the box — compose them with your own PSR-18 client and a cache. Treat any user-controlled jku/x5u as an SSRF vector.
  • X.509 only. createFromCertificate expects a real certificate, not a bare public key. Extracting the embedded public key is what it does; a CSR or a PEM public key file will fail.
  • OpenSSL/Sodium coupling. Ed25519 and Ed448 need libsodium and a modern OpenSSL build; on older distro images key generation fails at runtime, not at composer install.
  • Debugging a key. $jwk->all() dumps the full JWK array — the fastest way to confirm alg, use, and key_ops actually match your intent. $jwk->has('d') tells you whether it's a private key.
  • Extension points are thin by design: implement Analyzer for custom policy checks, and wrap JKUFactory/X5UFactory (rather than subclassing) for caching and authentication. The factories are final-ish static helpers — composition is the intended path.
  • Version churn. Namespaces are stable across v3→v4 (Jose\Component\KeyManagement), but the package name moved twice (jwt-key-mgmt → jwt-framework → jwt-library). Pin the package in composer.json and read the upgrade notes before the next minor.
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.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle