       (codecs/bytes->str)
       (json/parse-string true)))
 
-(defn parse-algorithm
-  "Parse algorithm name and return a
-  internal keyword representation of it."
-  [header]
-  (let [algname (:alg header)]
-    (keyword (.toLowerCase algname))))
-
-(defn get-verifier-for-algorithm
-  "Get verifier function for algorithm name."
-  [^Keyword alg]
-  (when (contains? *signers-map* alg)
-    (get-in *signers-map* [alg :verifier])))
-
-(defn get-signer-for-algorithm
-  "Get signer function for algorithm name."
-  [^Keyword alg]
-  (when (contains? *signers-map* alg)
-    (get-in *signers-map* [alg :signer])))
-
-(defn safe-encode
-  "Properly encode string into
-  safe url base64 encoding."
-  [^String input]
-  (-> input
-      (codecs/str->bytes)
-      (codecs/bytes->safebase64)))
-
-(defn calculate-signature
-  "Make a jws signature."
-  [pkey alg header claims]
-  (let [candidate (str/join "." [header claims])
-        signer    (get-signer-for-algorithm alg)]
-    (-> (signer candidate pkey)
-        (codecs/bytes->safebase64))))
+(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

  and verification, it will be reported in an
  either/left instance."
  [input pkey & [{:keys [max-age] :as opts}]]
  {:pre [(string? input)]}
  (let [[header claims signature] (str/split input #"\." 3)
        candidate (str/join "." [header claims])
        header (parse-header header)
        claims (parse-claims claims)
        algorithm (parse-algorithm header)
        signature (codecs/safebase64->bytes signature)
        verifier (get-verifier-for-algorithm algorithm)
        result (verifier candidate signature pkey)]
    (if (false? result)
      (either/left "Invalid token.")
      (let [now (timestamp)]
        (cond
          (and (:exp claims) (> now (:exp claims)))
          (either/left (format "Token is older than :exp (%s)" (:exp claims)))

          (and (:nbf claims) (> now (:nbf claims)))
          (either/left (format "Token is older than :nbf (%s)" (:nbf claims)))

          (and (:iat claims) (number? max-age) (> (- now (:iat claims)) max-age))
          (either/left (format "Token is older than max-age (%s)" max-age))

          :else
          (either/right claims))))))

(defn sign
  "Not monadic version of encode."
  [& args]
  (either/from-either (apply encode args)))

(defn unsign
  "Not monadic version of decode."
  [& args]
  (let [result (apply decode args)]
    (when (either/right? result)
      (either/from-either result))))

            [buddy.core.sign.rsapss :as rsapss]
            [buddy.core.sign.rsapkcs15 :as rsapkcs]
            [buddy.core.sign.ecdsa :as ecdsa]
            [buddy.sign.util :as util]
            [clojure.string :as str]
            [cheshire.core :as json]
            [cats.monad.exception :as exc]
            [slingshot.slingshot :refer [throw+]])

  (:import clojure.lang.Keyword))

(def ^{:doc "List of supported signing algorithms"
