Skip to content

Instantly share code, notes, and snippets.

@ggeoffrey
Last active February 16, 2024 07:57
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ggeoffrey/b72ed568be4914a990790ea6b09c2c66 to your computer and use it in GitHub Desktop.
Save ggeoffrey/b72ed568be4914a990790ea6b09c2c66 to your computer and use it in GitHub Desktop.
Checking a JWT validity using JWKs in Clojure (tested with Cognito)
(ns services.jwt
(:require [buddy.sign.jwt :as jwt]
[clojure.data.codec.base64 :as b64]
[clojure.string :as str]
[cheshire.core :as json]
[buddy.core.keys :as keys] ;; You need to use [buddy/buddy-core "1.5.0-SNAPSHOT"]
[clojure.java.io :as io]))
(defn decode-b64 [str] (String. (b64/decode (.getBytes str))))
(defn parse-json [s]
;; beware, I got some tokens from AWS Cognito where the last '}' was missing in the payload
(let [clean-str (if (str/ends-with? s "}") s (str s "}"))]
(json/parse-string clean-str keyword)))
(defn decode [token]
(let [[header payload _] (clojure.string/split token #"\.")]
{:header (parse-json (decode-b64 header))
:payload (parse-json (decode-b64 payload))}))
(def token "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.aUxz0yQGItWdwmzz-P9hn1Od-dm_fhjoswCluICgga8")
;; GET TOKEN CONTENT
(decode token)
;; => {:header {:alg "HS256", :typ "JWT"}, :payload {:sub "1234567890", :name "John Doe", :iat 1516239022}}
;; VERIFY TOKEN USING HS256
(jwt/unsign token "clojure" {:alg :hs256}) ;; "clojure" is the secret I put in the bottom left pane in https://jwt.io
;; VERIFY TOKEN USING RS256 (JWK)
(let [public-key (-> "keys/dev/jwks.json" io/resource slurp (json/parse-string keyword) :keys first keys/jwk->public-key)]
(try
(jwt/unsign token public-key {:alg :rs256})
(catch Throwable t
{:error true
:details (ex-data t)})))
;; => {:error true, :details {:type :validation, :cause :signature}}
;; :signature error since I got this token on https://jwt.io and tried to unsign it using my own JWK
;; I don't want to past a private token in this public gist ;) .
;; Drop a comment if you need more info.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment