Skip to content

Instantly share code, notes, and snippets.

@raymcdermott
Last active August 30, 2017 22:18
Show Gist options
  • Save raymcdermott/1f38ec455df433b96da789a70a4dd346 to your computer and use it in GitHub Desktop.
Save raymcdermott/1f38ec455df433b96da789a70a4dd346 to your computer and use it in GitHub Desktop.
IODC Discovery
; TODO: have a way to have this list provided / augmented by users
(def ^:private oidc-discovery
"Map from TLDs to discovery endpoints"
{"auth0.com" ".well-known/jwks.json"
"google.com" ".well-known/openid-configuration"})
(defn- get-jwt-data
"Obtain JWT related data and parse it into a Clojure map"
[endpoint]
(try
(-> @(client/get endpoint)
:body
bytes/to-string
string->edn)
(catch Exception e
; TODO 'proper' error handling
(println "Exception " e))))
(def ^:private one-day
(* 1000 ;milliseconds -> seconds
60 ;seconds -> minutes
60 ;mins -> hours
24))
;; It is not efficient to obtain these discovery docs on every verification
;; Compose the behaviour of these two caches to limit the number of and length of time
;; that certs that can be held in the cache
(def ^:private discovery-cache (atom (-> {}
(cache/fifo-cache-factory)
(cache/ttl-cache-factory :ttl one-day))))
(defn jwt-discovery-info
"Obtain the JWKs based on the issuer URL, cache the result"
[issuer-url]
(when-let [domain (last (string/split issuer-url #"/"))]
(when-let [discovery-url (some->> (first (keep #(re-find (re-pattern %) domain)
(keys oidc-discovery)))
(get oidc-discovery)
(str issuer-url))]
(if (cache/has? @discovery-cache discovery-url)
(get (cache/hit @discovery-cache discovery-url) discovery-url)
(when-let [discovery-doc (get-jwt-data discovery-url)]
(let [updated-cache (swap! discovery-cache #(cache/miss % discovery-url discovery-doc))]
(get updated-cache discovery-url)))))))
(defn cert->pem
[cert]
(keys/str->public-key
(str "-----BEGIN CERTIFICATE-----\n"
(string/join "\n" (string/join "\n" (re-seq #".{1,64}" cert)))
"\n-----END CERTIFICATE-----\n")))
; ---------->>>>>>> USAGE
(defn jwt-signing-info
[issuer kid]
(when-let [discovery-doc (jwt-discovery-info issuer)]
(when-let [signing-key (first (filter #(= kid (:kid %)) (:keys discovery-doc)))]
(let [public-key (cert->pem (first (:x5c signing-key)))
alg (keyword (string/lower-case (:alg signing-key)))]
{:key public-key :alg alg}))))
(defn verify-jwt
[token]
(let [decoded-jwt (decoded-jwt token)
issuer (get-in decoded-jwt [:payload :iss])
kid (get-in decoded-jwt [:header :kid])]
(when-let [jwt-signing-info (jwt-signing-info issuer kid)]
(jwt/unsign token (:key jwt-signing-info) {:alg (:alg jwt-signing-info)}))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment