forked from struhtanov/ring-jwt
-
Notifications
You must be signed in to change notification settings - Fork 2
/
jwt.clj
65 lines (55 loc) · 2.41 KB
/
jwt.clj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
(ns ring.middleware.jwt
(:require [clojure.spec.alpha :as s]
[ring.middleware.token :as token])
(:import (com.auth0.jwt.exceptions SignatureVerificationException AlgorithmMismatchException JWTVerificationException TokenExpiredException)))
(defn read-token-from-header
"Finds the token by searching the specified HTTP header (case-insensitive) for a bearer token."
[header-name]
(fn [{:keys [headers]}]
(some->> headers
(filter #(.equalsIgnoreCase header-name (key %)))
(first)
(val)
(re-find #"(?i)^Bearer (.+)$")
(last))))
(s/def ::alg-opts (s/and (s/keys :req-un [::token/alg]
:opt-un [::token/leeway-seconds])
(s/or :secret-opts ::token/secret-opts
:public-key-opts ::token/public-key-opts)))
(s/def ::issuers (s/map-of ::token/issuer ::alg-opts))
(s/def ::find-token-fn fn?)
(s/def ::reject-missing-token? boolean?)
(s/def ::opts (s/keys :req-un [::issuers]
:opt-un [::find-token-fn ::reject-missing-token?]))
(defn wrap-jwt
"Middleware that decodes a JWT token, verifies against the signature and then
adds the decoded claims to the incoming request under :claims.
If the JWT token exists but cannot be decoded then the token is considered tampered with and
a 401 response is produced.
If the JWT token does not exist, an empty :claims map is added to the incoming request."
[handler {:keys [find-token-fn issuers reject-missing-token?]
:or {reject-missing-token? false}
:as opts}]
(when-not (s/valid? ::opts opts)
(throw (ex-info "Invalid options." (s/explain-data ::opts opts))))
(fn [req]
(try
(if-let [token ((or find-token-fn (read-token-from-header "Authorization")) req)]
(if-let [alg-opts (get issuers (or (token/decode-issuer token) :no-issuer))]
(->> (token/decode token alg-opts)
(assoc req :claims)
(handler))
{:status 401
:body "Unknown issuer."})
(if reject-missing-token?
{:status 401
:body "No token found."}
(->> (assoc req :claims {})
(handler))))
(catch JWTVerificationException e
{:status 401
:body (ex-message e)}))))
(s/fdef wrap-jwt
:ret fn?
:args (s/cat :handler fn?
:opts ::opts))