diff --git a/include/jwt/base64.hpp b/include/jwt/base64.hpp
index 2460afb..761dcea 100644
--- a/include/jwt/base64.hpp
+++ b/include/jwt/base64.hpp
@@ -36,41 +36,41 @@ std::string base64_encode(const char* in, size_t len)
   std::string result;
   result.resize(128);
 
-  constexpr static const EMap bmap{};
+  constexpr static const EMap emap{};
 
   int i = 0;
-
+  int j = 0;
   for (; i < len - 2; i += 3) {
-    auto first  = in[i];
-    auto second = in[i+1];
-    auto third  = in[i+2];
+    auto& first  = in[i];
+    auto& second = in[i+1];
+    auto& third  = in[i+2];
 
-    result[i]     = bmap.at( (first >> 2) & 0x3F                           );
-    result[i + 1] = bmap.at(((first  & 0x03) << 4) | ((second & 0xF0) >> 4));
-    result[i + 2] = bmap.at(((second & 0x0F) << 2) | ((third  & 0xC0) >> 6));
-    result[i + 3] = bmap.at(                          (third  & 0x3F)      );
+    result[j++] = emap.at( (first >> 2) & 0x3F                           );
+    result[j++] = emap.at(((first  & 0x03) << 4) | ((second & 0xF0) >> 4));
+    result[j++] = emap.at(((second & 0x0F) << 2) | ((third  & 0xC0) >> 6));
+    result[j++] = emap.at(                          (third  & 0x3F)      );
   }
 
   switch (len % 3) {
   case 2:
   {
-    auto first  = in[i];
-    auto second = in[i+1];
+    auto& first  = in[i];
+    auto& second = in[i+1];
 
-    result[i]     = bmap.at( (first >> 2) & 0x3F                          );
-    result[i + 1] = bmap.at(((first & 0x03) << 4) | ((second & 0xF0) >> 4));
-    result[i + 2] = bmap.at(                         (second & 0x0F) << 2 );
-    result[i + 3] = '=';
+    result[j++] = emap.at( (first >> 2) & 0x3F                          );
+    result[j++] = emap.at(((first & 0x03) << 4) | ((second & 0xF0) >> 4));
+    result[j++] = emap.at(                         (second & 0x0F) << 2 );
+    result[j++] = '=';
     break;
   }
   case 1:
   {
     auto& first = in[i];
 
-    result[i]     = bmap.at((first >> 2) & 0x3F                          );
-    result[i + 1] = bmap.at((first & 0x03) << 4                          );
-    result[i + 2] = '=';
-    result[i + 3] = '=';
+    result[j++] = emap.at((first >> 2) & 0x3F);
+    result[j++] = emap.at((first & 0x03) << 4);
+    result[j++] = '=';
+    result[j++] = '=';
     break;
   }
   case 0:
@@ -135,7 +135,7 @@ std::string base64_decode(const char* in, size_t len)
   while (bytes_rem > 4)
   {
     // Error case in input
-    if (dmap.at(*in) == -1) return;
+    if (dmap.at(*in) == -1) return result;
 
     auto first  = dmap.at(in[0]);
     auto second = dmap.at(in[1]);
diff --git a/include/jwt/detail/meta.hpp b/include/jwt/detail/meta.hpp
new file mode 100644
index 0000000..4626c82
--- /dev/null
+++ b/include/jwt/detail/meta.hpp
@@ -0,0 +1,10 @@
+#ifndef JWT_META_HPP
+#define JWT_META_HPP
+
+namespace jwt {
+namespace detail {
+
+}
+} // END namespace jwt
+
+#endif
diff --git a/include/jwt/impl/jwt.ipp b/include/jwt/impl/jwt.ipp
new file mode 100644
index 0000000..af84bd8
--- /dev/null
+++ b/include/jwt/impl/jwt.ipp
@@ -0,0 +1,36 @@
+#ifndef JWT_IPP
+#define JWT_IPP
+
+namespace jwt {
+
+template <typename T>
+std::string to_json_str(const T& obj, bool pretty)
+{
+  return pretty ? obj.create_json_obj().dump(2)
+                : obj.create_json_obj().dump()
+                ;
+}
+
+
+template <typename T>
+std::ostream& write(std::ostream& os, const T& obj, bool pretty)
+{
+  pretty ? (os << std::setw(2) << obj.create_json_obj())
+         : (os                 << obj.create_json_obj())
+         ;
+
+  return os;
+}
+
+
+template <typename T>
+std::ostream& operator<< (std::ostream& os, const T& obj)
+{
+  os << obj.create_json_obj();
+  return os;
+}
+
+} // END namespace jwt
+
+
+#endif
diff --git a/include/jwt/json/test_json b/include/jwt/json/test_json
new file mode 100755
index 0000000..6bf91cf
Binary files /dev/null and b/include/jwt/json/test_json differ
diff --git a/include/jwt/json/test_json.cc b/include/jwt/json/test_json.cc
new file mode 100644
index 0000000..869d24f
--- /dev/null
+++ b/include/jwt/json/test_json.cc
@@ -0,0 +1,21 @@
+#include <iostream>
+#include <string>
+#include "./json.hpp"
+
+using json = nlohmann::json;
+
+void basic_json_test()
+{
+  json obj = json::object();
+  obj["test"] = "value-test";
+  obj["test-int"] = 42;
+
+  std::string jstr = obj.dump(0);
+  std::cout << jstr << std::endl;
+}
+
+int main() {
+  basic_json_test();
+
+  return 0;
+}
diff --git a/include/jwt/jwt.hpp b/include/jwt/jwt.hpp
index 86e5904..884dbf0 100644
--- a/include/jwt/jwt.hpp
+++ b/include/jwt/jwt.hpp
@@ -1,8 +1,23 @@
 #ifndef JWT_HPP
 #define JWT_HPP
 
+#include <cassert>
+#include <string>
+#include <ostream>
+
+#include "jwt/base64.hpp"
+#include "jwt/string_view.hpp"
+#include "jwt/detail/meta.hpp"
+#include "jwt/json/json.hpp"
+
+// For convenience
+using json_t = nlohmann::json;
+
 namespace jwt {
 
+/*!
+ * JWT signing algorithm.
+ */
 enum class algorithm
 {
   NONE = 0,
@@ -19,6 +34,239 @@ enum class algorithm
 };
 
 
+/*!
+ */
+string_view alg_to_str(enum algorithm alg) noexcept
+{
+  switch (alg) {
+    case algorithm::HS256: return "HS256";
+    case algorithm::HS384: return "HS384";
+    case algorithm::HS512: return "HS512";
+    case algorithm::RS256: return "RS256";
+    case algorithm::RS384: return "RS384";
+    case algorithm::RS512: return "RS512";
+    case algorithm::ES256: return "ES256";
+    case algorithm::ES384: return "ES384";
+    case algorithm::ES512: return "ES512";
+    case algorithm::TERM:  return "TERM";
+    case algorithm::NONE:  return "NONE";
+    default:               assert (0 && "Unknown Algorithm");
+  };
+
+  assert (0 && "Code not reached");
+}
+
+
+/*!
+ */
+enum class type
+{
+  JWT = 0,
+};
+
+
+/*!
+ */
+string_view type_to_str(enum type typ)
+{
+  switch (typ) {
+    case type::JWT: return "JWT";
+    default:        assert (0 && "Unknown type");
+  };
+
+  assert (0 && "Code not reached");
+}
+
+
+/*!
+ * Registered claim names.
+ */
+enum class registered_claims
+{
+  // Expiration Time claim
+  expiration = 0,
+  // Not Before Time claim
+  not_before,
+  // Issuer name claim
+  issuer,
+  // Audience claim
+  audience,
+  // Issued At Time claim 
+  issued_at,
+  // Subject claim
+  subject,
+  // JWT ID claim
+  jti,
+};
+
+
+/*!
+ */
+string_view reg_claims_to_str(enum registered_claims claim) noexcept
+{
+  switch (claim) {
+    case registered_claims::expiration: return "exp";
+    case registered_claims::not_before: return "nbf";
+    case registered_claims::issuer:     return "iss";
+    case registered_claims::audience:   return "aud";
+    case registered_claims::issued_at:  return "iat";
+    case registered_claims::subject:    return "sub";
+    case registered_claims::jti:        return "jti";
+    default:                            assert (0 && "Not a registered claim");
+  };
+
+  assert (0 && "Code not reached");
+}
+
+// Fwd declaration for friend functions to specify the 
+// default arguments
+// See: https://stackoverflow.com/a/23336823/434233
+template <typename T>
+std::string to_json_str(const T& obj, bool pretty=false);
+
+template <typename T>
+std::ostream& write(std::ostream& os, const T& obj, bool pretty=false);
+
+/*!
+ */
+struct write_interface
+{
+  /*!
+   */
+  template <typename T>
+  friend std::string to_json_str(const T& obj, bool pretty);
+
+  /*!
+   */
+  template <typename T>
+  friend std::ostream& write(
+      std::ostream& os, const T& obj, bool pretty);
+
+  /*!
+   */
+  template <typename T>
+  friend std::ostream& operator<< (std::ostream& os, const T& obj);
+};
+
+/*!
+ */
+template <typename Derived>
+struct base64_enc_dec
+{
+  std::string base64_encode(bool with_pretty = false) const
+  {
+    std::string jstr = to_json_str(*static_cast<const Derived*>(this), with_pretty);
+    return jwt::base64_encode(jstr.c_str(), jstr.length());
+  }
+
+  static std::string base64_decode(const std::string& encoded_str)
+  {
+    return jwt::base64_decode(encoded_str.c_str(), encoded_str.length());
+  }
+
+};
+
+
+/*!
+ * JWT Header.
+ */
+struct jwt_header: write_interface
+                 , base64_enc_dec<jwt_header>
+{
+public: // 'tors
+  /*!
+   */
+  jwt_header() = default;
+
+  /*!
+   */
+  jwt_header(enum algorithm alg, enum type typ = type::JWT)
+    : alg_(alg)
+    , typ_(typ)
+  {
+  }
+
+  /// Default Copy and assignment
+  jwt_header(const jwt_header&) = default;
+  jwt_header& operator=(const jwt_header&) = default;
+
+  ~jwt_header() = default;
+
+public: // Exposed APIs
+  /*!
+   * NOTE: Any previously saved json dump or the encoding of the
+   * header would not be valid after modifying the algorithm.
+   */
+  void algo(enum algorithm alg) noexcept
+  {
+    alg_ = alg;
+  }
+
+  /*!
+   */
+  enum algorithm algo() const noexcept
+  {
+    return alg_;
+  }
+
+  /*!
+   * NOTE: Any previously saved json dump or the encoding of the
+   * header would not be valid after modifying the type.
+   */
+  void typ(enum type typ) noexcept
+  {
+    typ_ = typ;
+  }
+
+  /*!
+   */
+  enum type typ() const noexcept
+  {
+    return typ_;
+  }
+
+  /*!
+   */
+  json_t create_json_obj() const
+  {
+    json_t obj = json_t::object();
+    obj["typ"] = type_to_str(typ_).to_string();
+    obj["alg"] = alg_to_str(alg_).to_string();
+
+    return obj;
+  }
+
+private: // Data members
+  /// The Algorithm to use for signature creation
+  enum algorithm alg_ = algorithm::NONE;
+
+  /// The type of header
+  enum type      typ_ = type::JWT;
+};
+
+/*!
+ */
+struct jwt_payload
+{
+};
+
+/*!
+ */
+struct jwt_signature
+{
+};
+
+
+/*!
+ */
+class jwt_object
+{
+};
+
+
 } // END namespace jwt
 
+
+#include "jwt/impl/jwt.ipp"
+
 #endif
diff --git a/include/jwt/string_view.hpp b/include/jwt/string_view.hpp
index f7c7500..e14ef93 100644
--- a/include/jwt/string_view.hpp
+++ b/include/jwt/string_view.hpp
@@ -342,6 +342,10 @@ private:
 };
 
 
+/// Helper typedef
+using string_view = basic_string_view<char>;
+
+
 } // END namespace jwt
 
 #include "jwt/impl/string_view.ipp"
diff --git a/include/jwt/test/test_jwt_header b/include/jwt/test/test_jwt_header
new file mode 100755
index 0000000..5ff066f
Binary files /dev/null and b/include/jwt/test/test_jwt_header differ
diff --git a/include/jwt/test/test_jwt_header.cc b/include/jwt/test/test_jwt_header.cc
new file mode 100644
index 0000000..5f79b38
--- /dev/null
+++ b/include/jwt/test/test_jwt_header.cc
@@ -0,0 +1,19 @@
+#include <iostream>
+#include "jwt/jwt.hpp"
+
+void test_basic_header()
+{
+  jwt::jwt_header hdr;
+  hdr = jwt::jwt_header{jwt::algorithm::HS256};
+  std::string jstr = to_json_str(hdr);
+  std::cout << jstr << std::endl;
+
+  std::string enc_str = hdr.base64_encode();
+  std::cout << "Base64: " << enc_str << std::endl;
+  std::cout << "Decoded: " << jwt::jwt_header::base64_decode(enc_str) << std::endl;
+}
+
+int main() {
+  test_basic_header();
+  return 0;
+}
diff --git a/include/jwt/test_stack_alloc b/include/jwt/test/test_stack_alloc
similarity index 100%
rename from include/jwt/test_stack_alloc
rename to include/jwt/test/test_stack_alloc
diff --git a/include/jwt/test_stack_alloc.cc b/include/jwt/test/test_stack_alloc.cc
similarity index 100%
rename from include/jwt/test_stack_alloc.cc
rename to include/jwt/test/test_stack_alloc.cc
diff --git a/include/jwt/test_sv b/include/jwt/test/test_sv
similarity index 100%
rename from include/jwt/test_sv
rename to include/jwt/test/test_sv
diff --git a/include/jwt/test_sv.cc b/include/jwt/test/test_sv.cc
similarity index 100%
rename from include/jwt/test_sv.cc
rename to include/jwt/test/test_sv.cc