 
 (defn parse-header
   "Parse jws header."
-  [^String headerdata]
-  (-> headerdata
-      (codecs/safebase64->bytes)
-      (codecs/bytes->str)
-      (json/parse-string true)))
+  [^String header]
+  (let [header (codecs/safebase64->str header)
+        {:keys [alg] :as header} (json/parse-string header true)]
+    (when (nil? alg)
+      (throw+ {:type :validation
+               :cause :header
+               :message "Missing `alg` key in header."}))
+    (merge {:alg (keyword (str/lower-case alg))}
+           (dissoc header :alg))))
 
 (defn parse-claims
   "Parse jws claims"

  json web token/signature."
  [claims pkey & [{:keys [alg exp nbf iat headers] :or {alg :hs256 headers {}}}]]
  {:pre [(map? claims)]}
  (let [header (encode-header alg headers)
        claims (encode-claims claims exp nbf iat)
        signature (calculate-signature pkey alg header claims)]
    (either/right (str/join "." [header claims signature]))))

(defn decode
  "Given a signed message, verify it and return

      (codecs/bytes->str)
      (json/parse-string true)))

(defmulti calculate-signature :alg)
(defmulti verify-signature :alg)

(defmethod calculate-signature :hs256
  [{:keys [key alg header claims]}]
  (-> (str/join "." [header claims])
      (hmac/hash key :sha256)
      (codecs/bytes->safebase64)))

(defmethod calculate-signature :hs512
  [{:keys [key alg header claims]}]
  (-> (str/join "." [header claims])
      (hmac/hash key :sha512)
      (codecs/bytes->safebase64)))

(defmethod calculate-signature :rs256
  [{:keys [key alg header claims]}]
  (-> (str/join "." [header claims])
      (rsapkcs/sign key :sha256)
      (codecs/bytes->safebase64)))

(defmethod calculate-signature :rs512
  [{:keys [key alg header claims]}]
  (-> (str/join "." [header claims])
      (rsapkcs/sign key :sha512)
      (codecs/bytes->safebase64)))

(defmethod calculate-signature :ps256
  [{:keys [key alg header claims]}]
  (-> (str/join "." [header claims])
      (rsapss/sign key :sha256)
      (codecs/bytes->safebase64)))

(defmethod calculate-signature :ps512
  [{:keys [key alg header claims]}]
  (-> (str/join "." [header claims])
      (rsapss/sign key :sha512)
      (codecs/bytes->safebase64)))

(defmethod calculate-signature :es256
  [{:keys [key alg header claims]}]
  (-> (str/join "." [header claims])
      (ecdsa/sign key :sha256)
      (codecs/bytes->safebase64)))

(defmethod calculate-signature :es512
  [{:keys [key alg header claims]}]
  (-> (str/join "." [header claims])
      (ecdsa/sign key :sha512)
      (codecs/bytes->safebase64)))

(defmethod verify-signature :hs256
  [{:keys [alg signature key header claims]}]
  (-> (str/join "." [header claims])
      (hmac/verify signature key :sha256)))

(defmethod verify-signature :hs512
  [{:keys [alg signature key header claims]}]
  (-> (str/join "." [header claims])
      (hmac/verify signature key :sha512)))

(defmethod verify-signature :rs256
  [{:keys [alg signature key header claims]}]
  (-> (str/join "." [header claims])
      (rsapkcs/verify signature key :sha256)))

(defmethod verify-signature :rs512
  [{:keys [alg signature key header claims]}]
  (-> (str/join "." [header claims])
      (rsapkcs/verify signature key :sha512)))

(defmethod verify-signature :ps256
  [{:keys [alg signature key header claims]}]
  (-> (str/join "." [header claims])
      (rsapss/verify signature key :sha256)))

(defmethod verify-signature :ps512
  [{:keys [alg signature key header claims]}]
  (-> (str/join "." [header claims])
      (rsapss/verify signature key :sha512)))

(defmethod verify-signature :es256
  [{:keys [alg signature key header claims]}]
  (-> (str/join "." [header claims])
      (ecdsa/verify signature key :sha256)))

(defmethod verify-signature :es512
  [{:keys [alg signature key header claims]}]
  (-> (str/join "." [header claims])
      (ecdsa/verify signature key :sha512)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Public Api
