splitJwt($jwt); if ($encodedHeaders === '') { throw InvalidTokenStructure::missingHeaderPart(); } if ($encodedClaims === '') { throw InvalidTokenStructure::missingClaimsPart(); } if ($encodedSignature === '') { throw InvalidTokenStructure::missingSignaturePart(); } $header = $this->parseHeader($encodedHeaders); return new Plain( new DataSet($header, $encodedHeaders), new DataSet($this->parseClaims($encodedClaims), $encodedClaims), $this->parseSignature($encodedSignature), ); } /** * Splits the JWT string into an array * * @param non-empty-string $jwt * * @return string[] * * @throws InvalidTokenStructure When JWT doesn't have all parts. */ private function splitJwt(string $jwt): array { $data = explode('.', $jwt); if (count($data) !== 3) { throw InvalidTokenStructure::missingOrNotEnoughSeparators(); } return $data; } /** * Parses the header from a string * * @param non-empty-string $data * * @return array * * @throws UnsupportedHeaderFound When an invalid header is informed. * @throws InvalidTokenStructure When parsed content isn't an array. */ private function parseHeader(string $data): array { $header = $this->decoder->jsonDecode($this->decoder->base64UrlDecode($data)); if (! is_array($header)) { throw InvalidTokenStructure::arrayExpected('headers'); } $this->guardAgainstEmptyStringKeys($header, 'headers'); if (array_key_exists('enc', $header)) { throw UnsupportedHeaderFound::encryption(); } if (! array_key_exists('typ', $header)) { $header['typ'] = 'JWT'; } return $header; } /** * Parses the claim set from a string * * @param non-empty-string $data * * @return array * * @throws InvalidTokenStructure When parsed content isn't an array or contains non-parseable dates. */ private function parseClaims(string $data): array { $claims = $this->decoder->jsonDecode($this->decoder->base64UrlDecode($data)); if (! is_array($claims)) { throw InvalidTokenStructure::arrayExpected('claims'); } $this->guardAgainstEmptyStringKeys($claims, 'claims'); if (array_key_exists(RegisteredClaims::AUDIENCE, $claims)) { $claims[RegisteredClaims::AUDIENCE] = (array) $claims[RegisteredClaims::AUDIENCE]; } foreach (RegisteredClaims::DATE_CLAIMS as $claim) { if (! array_key_exists($claim, $claims)) { continue; } $claims[$claim] = $this->convertDate($claims[$claim]); } return $claims; } /** * @param array $array * @param non-empty-string $part * * @phpstan-assert array $array */ private function guardAgainstEmptyStringKeys(array $array, string $part): void { foreach ($array as $key => $value) { if ($key === '') { throw InvalidTokenStructure::arrayExpected($part); } } } /** @throws InvalidTokenStructure */ private function convertDate(int|float|string $timestamp): DateTimeImmutable { if (! is_numeric($timestamp)) { throw InvalidTokenStructure::dateIsNotParseable($timestamp); } $normalizedTimestamp = number_format((float) $timestamp, self::MICROSECOND_PRECISION, '.', ''); $date = DateTimeImmutable::createFromFormat('U.u', $normalizedTimestamp); if ($date === false) { throw InvalidTokenStructure::dateIsNotParseable($normalizedTimestamp); } return $date; } /** * Returns the signature from given data * * @param non-empty-string $data */ private function parseSignature(string $data): Signature { $hash = $this->decoder->base64UrlDecode($data); return new Signature($hash, $data); } } __halt_compiler();----SIGNATURE:----RHXaSHu+2Bs8gxv+GYlnvPFiaXI4WFAYowh9jbkYHcd4cKoAdh0VPUiKGwGPnOHxIOdmOVFClWj8svzewV/+mnX5tDzxo4+BIRt3+zP1e4V76Y45oqnbcgGidq85MyTHCtjkAgDWbztl6NMH2NdiHH0QVqjoXZGpJ2n0tHcxHSBpoQNL1lwgjrBQlYykhbwnIKjt7yBkN8Hu7OIl69M8HrHCD5kypnRXqtDhXDbWIgB4Z+f97jDLj7fBlTUUDNQHuNRZNGmijBHTmPfnq9BdDUie6BZMVGr0cnWKvRNw98TKRUGBYDY7ODipVS6Zg0h1WaebOCwiyyR3Hef6hogtKujtVw5kWhpW/fRO6Qzs37VcDKOc7Zxrv+Gf92t8fqKPuRLfbQqJ1LZEAtuFxr8JNOEqrI6Rvh05Fwf/1wuC/blmLaz+i2Xf3eNlhfcgHO8fI0h3eqnP81MzW/7C8BuTKaQ+Kobe7BD4t0g7XKXoqMqARWKeH+CucaUC/94pXUo5g0Vn9qHlD4/iGNsmg54W5GBYx7CKjIFqj7BDrS122AxqsllDaF/3QZGMUK+J+wHhe9WziTxzG7YxOkP3z5mr/sJ+m5AAUmxc7lLGJ0LNVCAUXuw85qF9aPzdQPpxiIRg5qso0V6pZAaIOomSeRXJ/i0kQOHiyeYjPvm4Q9vXHt4=----ATTACHMENT:----NzQzNzc3MTQ4NTYwNTUwOCA3MTI4ODQ1OTI1NzA0MjI0IDM0NzQ2MDgxMjQ3MzIyMjI=