diff --git a/src/Fits.php b/src/Fits.php
index d9a2f8d..f3d06b6 100644
--- a/src/Fits.php
+++ b/src/Fits.php
@@ -17,6 +17,7 @@ class Fits
     private $byteStream;
     private string $path;
     public readonly int $size;
+    public readonly string $headerBlock;
 
     /**
     * @throws InvalidFitsException, InvalidPathException
@@ -34,6 +35,8 @@ class Fits
         if (! $this->validate()) {
             throw new InvalidFitsException('The opened file is not a valid FITS image (invalid block size)');
         }
+
+        $this->headerBlock = $this->extractHeader();
     }
     /**
     * Validate the given FITS file based on block sizes
@@ -52,11 +55,16 @@ class Fits
         return true;
     }
     /**
-    * @todo Return FitsHeader object
-    * @return string
+    * @return FitsHeader
     */
-    #[\ReturnTypeWillChange]
-    public function header(): string
+    public function header(): FitsHeader
+    {
+        return new FitsHeader($this->headerBlock);
+    }
+    /**
+    * Extract the FITS header block as a string
+    */
+    private function extractHeader(): string
     {
         $contents = fread($this->byteStream, $this->size);
         $end = strpos($contents, 'END');
@@ -66,8 +74,8 @@ class Fits
         return substr($contents, 0, $headerEnd);
     }
 
-    public function fromPath(string $path): void
+    public function writeTo(string $path): void
     {
-        $this->byteStream = fopen($path, 'rb');
+        // TODO
     }
 }
diff --git a/src/FitsHeader.php b/src/FitsHeader.php
index 068256f..6a0e26f 100644
--- a/src/FitsHeader.php
+++ b/src/FitsHeader.php
@@ -4,7 +4,52 @@ declare(strict_types=1);
 
 namespace Dumbastro\FitsPhp;
 
+use Dumbastro\FitsPhp\Keyword;
+
 class FitsHeader
 {
+    private string $headerBlock;
+    /**
+    * @var Keyword[] $keywords
+    */
+    public readonly array $keywords;
+
+    public function __construct(string $headerBlock)
+    {
+        $this->headerBlock = $headerBlock;
+        $this->keywords = $this->readKeywords();
+    }
+    /**
+    * Initialize the keyword records array
+    * 
+    * From the spec: each keyword record, including
+    * any comments, is at most 80 bytes long
+    * @return Keyword[]
+    */
+    private function readKeywords(): array
+    {
+        $records = str_split($this->headerBlock, 80);
+
+        $records = array_filter(
+            $records,
+            fn (string $r) => trim($r) !== '' && !str_starts_with($r, 'END')
+        );
+
+        $keywords = [];
+
+        foreach ($records as $record) {
+            $splitByComment = explode('/', $record);
+            $comment = isset($splitByComment[1]) ? trim($splitByComment[1]) : null;
+            $nameValue = explode('=', $splitByComment[0]);
+
+            $keywords[] = new Keyword(
+                name : trim($nameValue[0]),
+                value : trim($nameValue[1]),
+                comment : $comment,
+            );
+        }
+
+        return $keywords;
+    }
 }
 
diff --git a/src/Keyword.php b/src/Keyword.php
new file mode 100644
index 0000000..0fb55ce
--- /dev/null
+++ b/src/Keyword.php
@@ -0,0 +1,18 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Dumbastro\FitsPhp;
+
+/**
+* A FITS keyword record
+* @todo Add types for max lengths?
+*/
+readonly class Keyword
+{
+    public function __construct(
+        public string $name,
+        public string $value,
+        public ?string $comment,
+    ) {}
+}