This commit is contained in:
2026-05-17 20:07:18 -05:00
parent 1025d48877
commit 24169162aa
5 changed files with 1821 additions and 42 deletions

View File

@@ -4,8 +4,6 @@ namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
class JwtAuthMiddleware
{
@@ -24,20 +22,24 @@ class JwtAuthMiddleware
$token = $matches[1];
$publicKey = str_replace('\\n', "\n", env('JWT_PUBLIC_KEY_PEM'));
[$header, $payload, $signature] = $this->decodeToken($token);
$decoded = JWT::decode($token, new Key($publicKey, 'RS256'));
if (($header['alg'] ?? null) !== 'RS256') {
return response()->json(['message' => 'Invalid token algorithm'], 401);
}
if (
$decoded->iss !== env('JWT_ISSUER') ||
$decoded->aud !== env('JWT_AUDIENCE') ||
empty($decoded->sub)
!$this->signatureIsValid($token, $signature) ||
($payload['iss'] ?? null) !== config('jwt.issuer') ||
($payload['aud'] ?? null) !== config('jwt.audience') ||
empty($payload['sub']) ||
$this->tokenIsExpired($payload)
) {
return response()->json(['message' => 'Invalid token'], 401);
}
$request->attributes->set('auth', [
'id' => $decoded->sub,
'id' => $payload['sub'],
'token' => $token
]);
@@ -47,4 +49,68 @@ class JwtAuthMiddleware
return response()->json(['message' => 'Invalid or expired token'], 401);
}
}
}
private function decodeToken(string $token): array
{
$parts = explode('.', $token);
if (count($parts) !== 3) {
throw new \InvalidArgumentException('Invalid token structure');
}
return [
$this->base64UrlDecodeJson($parts[0]),
$this->base64UrlDecodeJson($parts[1]),
$this->base64UrlDecode($parts[2]),
];
}
private function base64UrlDecodeJson(string $value): array
{
$decoded = json_decode($this->base64UrlDecode($value), true);
if (!is_array($decoded)) {
throw new \InvalidArgumentException('Invalid token payload');
}
return $decoded;
}
private function base64UrlDecode(string $value): string
{
$value .= str_repeat('=', (4 - strlen($value) % 4) % 4);
$decoded = base64_decode(strtr($value, '-_', '+/'), true);
if ($decoded === false) {
throw new \InvalidArgumentException('Invalid base64url value');
}
return $decoded;
}
private function signatureIsValid(string $token, string $signature): bool
{
[$header, $payload] = explode('.', $token, 3);
$publicKey = str_replace('\\n', "\n", (string) config('jwt.public_key'));
if ($publicKey === '') {
return false;
}
return openssl_verify(
$header . '.' . $payload,
$signature,
$publicKey,
OPENSSL_ALGO_SHA256
) === 1;
}
private function tokenIsExpired(array $payload): bool
{
if (!isset($payload['exp']) || !is_numeric($payload['exp'])) {
return true;
}
return time() >= (int) $payload['exp'];
}
}