secret = $secret ?: require_env('JWT_SECRET'); $this->ttl = ($ttlSeconds !== null && $ttlSeconds > 0) ? $ttlSeconds : self::DEFAULT_TTL; } /** * Create a signed token embedding request metadata. * * @param array $payload */ public function createToken(array $payload): string { $now = time(); $data = array_merge($payload, [ 'iat' => $now, 'exp' => $now + $this->ttl, 'ctx' => self::TOKEN_CONTEXT, ]); return jwt_encode($data, $this->secret); } /** * Validate a token and return its payload if valid. */ public function parseToken(?string $token): ?array { if (!is_string($token) || $token === '') { return null; } $payload = jwt_decode($token, $this->secret); if (!is_array($payload)) { return null; } if (($payload['ctx'] ?? null) !== self::TOKEN_CONTEXT) { return null; } $exp = (int)($payload['exp'] ?? 0); if ($exp > 0 && $exp < time()) { return null; } return $payload; } }