53 lines
1.6 KiB
PHP
53 lines
1.6 KiB
PHP
<?php
|
|
/**
|
|
* Simple JWT (HMAC SHA256)
|
|
*/
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Core;
|
|
|
|
final class JWT
|
|
{
|
|
private static function base64UrlEncode(string $data): string
|
|
{
|
|
return str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($data));
|
|
}
|
|
|
|
private static function base64UrlDecode(string $data): string
|
|
{
|
|
return base64_decode(str_replace(['-', '_'], ['+', '/'], $data));
|
|
}
|
|
|
|
public static function encode(array $payload, string $secret): string
|
|
{
|
|
$header = json_encode(['typ' => 'JWT', 'alg' => 'HS256']);
|
|
$base64UrlHeader = self::base64UrlEncode($header);
|
|
$base64UrlPayload = self::base64UrlEncode(json_encode($payload));
|
|
|
|
$signature = hash_hmac('sha256', $base64UrlHeader . "." . $base64UrlPayload, $secret, true);
|
|
$base64UrlSignature = self::base64UrlEncode($signature);
|
|
|
|
return $base64UrlHeader . "." . $base64UrlPayload . "." . $base64UrlSignature;
|
|
}
|
|
|
|
public static function decode(string $token, string $secret): ?array
|
|
{
|
|
$parts = explode('.', $token);
|
|
if (count($parts) !== 3) return null;
|
|
|
|
[$header, $payload, $signature] = $parts;
|
|
|
|
$expectedSignature = self::base64UrlEncode(hash_hmac('sha256', $header . "." . $payload, $secret, true));
|
|
|
|
if (!hash_equals($expectedSignature, $signature)) return null;
|
|
|
|
$decodedPayload = json_decode(self::base64UrlDecode($payload), true);
|
|
|
|
// Check expiry
|
|
if (isset($decodedPayload['exp']) && $decodedPayload['exp'] < time()) return null;
|
|
|
|
return $decodedPayload;
|
|
}
|
|
}
|