Daycry JWT¶
JWT (JSON Web Token) for CodeIgniter 4, built on lcobucci/jwt 5 — HMAC, RSA and ECDSA, an immutable façade, and key rotation. Secure by default: it fails loudly instead of signing with a weak or missing key.
Features¶
-
HMAC, RSA & ECDSA
One config toggle (
algorithmType) switches between symmetric HMAC and asymmetric RSA/ECDSA. The signer andalgorithmTypemust agree — a mismatch fails fast with a clear message, not a cryptic key error. -
Immutable façade
Every
with*()customiser returns a new instance —withSplitData,withExpiresAt,withLeeway,withIssuer,withAudience,withIdentifier,withHeader,withClaims— so the shared config is never mutated across requests. -
Key rotation (
kid)
Stamp a
kidheader and verify against a per-kidkey map, so you can roll keys with zero downtime. An attacker-chosenkidcan never downgrade the verifier. -
Fail-closed by default
Missing
signer/issuer/audience/identifierthrows (nulland""rejected).decode()refuses to skip signature verification, andjwt:keyenforces a 256-bit minimum. -
Validated reads
decode(),getPayload(),getClaims()andgetClaim()all validate first. The parse-only helpers (isExpired,extractClaimsUnsafe) are clearly marked and log a warning so misuse is visible. -
Spark commands
jwt:key(HMAC secret to.env),jwt:keypair(RSA/ECDSA PEM pair, curve-aware), andjwt:publish(config to your app) — auto-registered with Spark.
Quick start¶
// Throws on failure…
$claims = $jwt->decode($token); // Lcobucci\JWT\Token\Plain
echo $claims->claims()->get('uid'); // "user-42"
// …or get the original payload back (auto-decodes compact JSON):
$payload = $jwt->getPayload($token); // ['user_id' => 42, 'role' => 'admin']
// …or the non-throwing flow:
if ($jwt->tryDecode($maybeBad) === null) {
return $this->response->setStatusCode(401);
}
Security, by default¶
-
Signature always verified
If
validate = truebutvalidateClaimsomitsSignedWith,decode()throws instead of silently skipping verification. Tampered tokens (signature, header or payload) are rejected. -
No stale clocks
The time constraints (
LooseValidAt/StrictValidAt) are rebuilt per call and always use the current clock — never a frozen one. Only the stateless signer/key configuration is memoized. -
Tested & analysed
A focused PHPUnit suite (expiry, leeway,
nbf, tampering, encrypted keys, key rotation) plus PHPStan level 8, Psalm and Rector keep the library correct and clean.