NovinkaZverejnili sme 50+ Laravel balíkov ako open source
Custom AI apps, agents and automation — Roundly ConsultingRoundly
Všetky balíky

Jose\Jws podpisuje a overuje kompaktné JWS (header.payload.signature). Overovanie je zámerne striktné: vynucuje štruktúru, limit 8 KB, pripnutie algoritmu pred kontrolou podpisu a odmietnutie crit — nič viac. Časové kontroly sú voliteľné:

use RoundlyConsulting\Crypto\Facades\Crypto;
use RoundlyConsulting\Crypto\Signature\Algorithm;

// Sign with the private half, verify with the public half
$private = Crypto::keys()->ec()->fromStorageOrGenerate('local', 'keys/ec.pem');   // P-256
$public  = Crypto::keys()->ec()->public($private->publicPem());

$token  = Crypto::jws()->sign(['kid' => 'k1'], ['sub' => 'alice', 'exp' => now()->addHour()->timestamp], Crypto::es($private));
$claims = Crypto::jws()->verify($token, Crypto::es($public), Algorithm::ES256);
$claims->assertTemporal(leeway: 30);   // opt-in: throws if expired / not yet valid
$sub = $claims->string('sub');

// Shared-secret tier: an HS256 signer from YOUR config key
$hs = Crypto::hs(Crypto::keys()->hmac()->fromConfig('tokens.secret'));

Alebo volajte priamo triedy, ktoré fasáda sprístupňuje:

use RoundlyConsulting\Crypto\Jose\Jws;
use RoundlyConsulting\Crypto\Signature\Algorithm;
use RoundlyConsulting\Crypto\Signature\Hs;
use RoundlyConsulting\Crypto\Signature\Key\HmacSecret;

$jws = new Jws;
$signer = new Hs(HmacSecret::fromString($secret)); // ≥32 random bytes

$token = $jws->sign(['kid' => 'k1'], ['sub' => 'alice', 'exp' => now()->addHour()->timestamp], $signer);

$claims = $jws->verify($token, $signer, Algorithm::HS256);
$claims->assertTemporal(leeway: 30);   // opt-in: throws if expired / not yet valid
$sub = $claims->string('sub');

Čo verify() kontroluje a v akom poradí

  • Algoritmus verifiera sa musí zhodovať s očakávaným (AlgorithmMismatchException).
  • Tokeny nad Jws::MAX_ENCODED_BYTES (8192) sa odmietnu (MalformedTokenException).
  • Token musí mať presne tri segmenty a hlavička crit sa odmietne.
  • alg v hlavičke sa musí reťazcovo zhodovať s očakávaným algoritmom ešte pred kontrolou podpisu — to blokuje downgrade na alg:none aj zámenu RS256↔HS256.
  • Nakoniec sa overí podpis (pri zlyhaní InvalidSignatureException).

Kľúč ani algoritmus sa nikdy nevyberajú podľa hlavičky tokenu. sign() vždy zapíše do hlavičky typ: JWT a alg signera — alg sa nedá prepísať — a JSON kóduje deterministicky, takže fixtures sa reprodukujú bajt po bajte. Claimy sú vždy JSON objekt (RFC 7519 §7.2): bez claimov sa zakódujú ako {}, nikdy ako [], ktoré PHP urobí z prázdneho poľa, a verify() odmietne hlavičku či payload, ktoré nie sú JSON objekt (MalformedTokenException).

RSA, ECDSA a EdDSA

Ďalšie úrovne fungujú rovnako s Rs/Es a RsaKey/EcKey. RSA dostane úroveň ako argument; ECDSA ju prečíta z krivky kľúča:

use RoundlyConsulting\Crypto\Signature\Rs;
use RoundlyConsulting\Crypto\Signature\Es;
use RoundlyConsulting\Crypto\Signature\Key\RsaKey;
use RoundlyConsulting\Crypto\Signature\Key\EcKey;

$token  = $jws->sign([], ['sub' => 'bob', 'exp' => $exp], new Rs(RsaKey::private($privatePem), Algorithm::RS512));
$claims = $jws->verify($token, new Rs(RsaKey::public($publicPem), Algorithm::RS512), Algorithm::RS512);

// ES512 on a P-521 key — the curve fixes the digest:
$es = $jws->sign([], ['sub' => 'kim'], new Es(EcKey::private($p521Pem)));
$jws->verify($es, new Es(EcKey::public($p521PublicPem)), Algorithm::ES512);

Signer vytvorený zo súkromného kľúča aj overuje — kontroluje voči odvodenej verejnej polovici —, takže služba, ktorá tokeny sama vydáva aj kontroluje, môže obom volaniam odovzdať tú istú inštanciu Rs alebo Es.

EdDSA (Ed25519) podpisuje aj overuje, ak je k dispozícii ext-sodium:

use RoundlyConsulting\Crypto\Signature\EdDSA;
use RoundlyConsulting\Crypto\Signature\Key\OkpKey;

$key = OkpKey::generate();                          // or OkpKey::fromSecretKey($sk)
$token = $jws->sign([], ['sub' => 'ed'], new EdDSA($key));
$jws->verify($token, new EdDSA(OkpKey::ed25519($key->publicKey)), Algorithm::EdDSA);

Flattened JWS (ACME)

flattened() vytvorí flattened JWS podľa RFC 7515 §7.2.2, ako ho používa ACME. alg sa zlúči do chránenej hlavičky a prázdny payload sa zakóduje ako prázdny segment (ACME POST-as-GET). Vrátený FlattenedJws implementuje JsonSerializable:

use RoundlyConsulting\Crypto\Signature\Key\RsaKey;
use RoundlyConsulting\Crypto\Signature\Rs;

$flattened = $jws->flattened(
    protected: ['nonce' => $nonce, 'url' => $url],
    payload:   $payloadJson,                          // '' encodes to an empty segment (POST-as-GET)
    signer:    new Rs(RsaKey::private($pem)),
);

$wire = json_encode($flattened);   // {"protected":"…","payload":"…","signature":"…"}

Claimy

Úspešné verify() vráti nemenný objekt Claims s typovanými, validujúcimi prístupmi. Pravidlá pre claimy — vydavateľ, publikum, rozsah — zostávajú na vás:

$claims->has('scope');          // bool
$claims->get('aud');            // mixed, null when absent
$claims->require('iss');        // mixed — throws ClaimMismatchException when absent

$sub    = $claims->string('sub');
$scopes = $claims->list('scope');   // list<string>
$issued = $claims->int('iat');
$all    = $claims->all();
MetódaVraciaVyhadzuje
has($name)bool—
get($name)mixedNikdy — ak chýba, vráti null.
require($name)mixedClaimMismatchException, ak chýba.
string($name)stringClaimMismatchException, ak chýba alebo nie je reťazec.
int($name)intClaimMismatchException, ak chýba, nie je celé číslo (1.0 prejde, 1.5 nie) alebo je to celé číslo mimo 64-bitového rozsahu.
list($name)list<string>ClaimMismatchException, ak chýba alebo nie je zoznam reťazcov.
all()array—
assertTemporal($leeway = 0)voidTokenExpiredException alebo TokenNotYetValidException.

Voliteľná časová validácia

assertTemporal() postupuje podľa RFC 7519: exp je povinný a musí byť v budúcnosti; nbf a iat, ak sú prítomné, nesmú byť v budúcnosti. Tolerancia (v sekundách) pohltí posun hodín medzi vydavateľom a overovateľom a aktuálny čas sa číta cez CarbonImmutable::now(), takže ho v testoch pripnete cez setTestNow():

use RoundlyConsulting\Crypto\Jose\TokenExpiredException;
use RoundlyConsulting\Crypto\Jose\TokenNotYetValidException;

try {
    $claims->assertTemporal(leeway: 30);   // seconds of clock-skew tolerance
} catch (TokenExpiredException $e) {
    // exp has passed (exp is required)
} catch (TokenNotYetValidException $e) {
    // nbf or iat is in the future
}

Prejavte lásku k open source

Tento balík je zadarmo pod licenciou MIT. Ak vám šetrí čas, jednorazový príspevok alebo členstvo na Patreone nám pomôže ho ďalej udržiavať, testovať a dokumentovať.

Ďalšie spôsoby podpory vrátane kryptomien

Odoslaním daru súhlasíte s našimi podmienkami prijímania darov.

Chcete to zabudovať do svojho produktu?

Naše balíky integrujeme do zákazkových Laravel a AI riešení. Napíšte nám, na čom pracujete, a ozveme sa do 48 hodín.