Add better approach for cookie token decoding

Remove unnecesary decoding for old tokens and add key identifier
and versioning to cookie tokens for handle future changes.
This commit is contained in:
Andrey Antukh
2025-11-18 21:10:02 +01:00
parent 4f29156929
commit a487dfe004
3 changed files with 54 additions and 30 deletions

View File

@@ -14,6 +14,7 @@
[app.config :as cf] [app.config :as cf]
[app.http :as-alias http] [app.http :as-alias http]
[app.http.errors :as errors] [app.http.errors :as errors]
[app.tokens :as tokens]
[app.util.pointer-map :as pmap] [app.util.pointer-map :as pmap]
[cuerdas.core :as str] [cuerdas.core :as str]
[yetti.adapter :as yt] [yetti.adapter :as yt]
@@ -272,9 +273,24 @@
process-request process-request
(fn [request] (fn [request]
(if-let [{:keys [type token] :as auth} (get-token request)] (if-let [{:keys [type token] :as auth} (get-token request)]
(if-let [decode-fn (get decoders type)] (let [decode-fn (get decoders type)]
(if (= type :cookie)
(let [metadata (tokens/decode-header token)]
;; NOTE: we only proceed to decode claims on new
;; cookie tokens. The old cookies dont need to be
;; decoded because they use the token string as ID
(if (and (= (:kid metadata) 1)
(= (:ver metadata) 1)
(some? decode-fn))
(assoc request ::http/auth-data (assoc auth
:claims (decode-fn token)
:metadata metadata))
(assoc request ::http/auth-data (assoc auth :metadata {:ver 0}))))
(if decode-fn
(assoc request ::http/auth-data (assoc auth :claims (decode-fn token))) (assoc request ::http/auth-data (assoc auth :claims (decode-fn token)))
(assoc request ::http/auth-data auth)) (assoc request ::http/auth-data auth))))
request))] request))]
(fn [request] (fn [request]

View File

@@ -158,14 +158,15 @@
(defn- assign-token (defn- assign-token
[cfg session] [cfg session]
(let [token (tokens/generate cfg (let [claims {:iss "authentication"
{:iss "authentication"
:aud "penpot" :aud "penpot"
:sid (:id session) :sid (:id session)
:iat (:modified-at session) :iat (:modified-at session)
:uid (:profile-id session) :uid (:profile-id session)
:sso-provider-id (:sso-provider-id session) :sso-provider-id (:sso-provider-id session)
:sso-session-id (:sso-session-id session)})] :sso-session-id (:sso-session-id session)}
header {:kid 1 :ver 1}
token (tokens/generate cfg claims header)]
(assoc session :token token))) (assoc session :token token)))
(defn create-fn (defn create-fn
@@ -225,13 +226,14 @@
[handler {:keys [::manager] :as cfg}] [handler {:keys [::manager] :as cfg}]
(assert (manager? manager) "expected valid session manager") (assert (manager? manager) "expected valid session manager")
(fn [request] (fn [request]
(let [{:keys [type token claims]} (get request ::http/auth-data)] (let [{:keys [type token claims metadata]} (get request ::http/auth-data)]
(cond (cond
(= type :cookie) (= type :cookie)
(let [session (if-let [sid (:sid claims)] (let [session (case (:ver metadata)
(read-session manager sid)
;; BACKWARD COMPATIBILITY WITH OLD TOKENS ;; BACKWARD COMPATIBILITY WITH OLD TOKENS
(read-session manager token)) 0 (read-session manager token)
1 (some->> (:sid claims) (read-session manager))
nil)
request (cond-> request request (cond-> request
(some? session) (some? session)
@@ -240,7 +242,7 @@
response (handler request)] response (handler request)]
(if (renew-session? session) (if (and session (renew-session? session))
(let [session (->> session (let [session (->> session
(update-session manager) (update-session manager)
(assign-token cfg))] (assign-token cfg))]
@@ -248,11 +250,11 @@
response)) response))
(= type :bearer) (= type :bearer)
(let [session (if-let [sid (:sid claims)] (let [session (case (:ver metadata)
(read-session manager sid)
;; BACKWARD COMPATIBILITY WITH OLD TOKENS ;; BACKWARD COMPATIBILITY WITH OLD TOKENS
(read-session manager token)) 0 (read-session manager token)
1 (some->> (:sid claims) (read-session manager))
nil)
request (cond-> request request (cond-> request
(some? session) (some? session)
(-> (assoc ::profile-id (:profile-id session)) (-> (assoc ::profile-id (:profile-id session))

View File

@@ -15,8 +15,9 @@
[buddy.sign.jwe :as jwe])) [buddy.sign.jwe :as jwe]))
(defn generate (defn generate
[{:keys [::setup/props] :as cfg} claims] ([cfg claims] (generate cfg claims nil))
(assert (contains? cfg ::setup/props)) ([{:keys [::setup/props] :as cfg} claims header]
(assert (contains? props :tokens-key) "expect props to have tokens-key")
(let [tokens-key (let [tokens-key
(get props :tokens-key) (get props :tokens-key)
@@ -27,7 +28,12 @@
(d/without-nils) (d/without-nils)
(t/encode))] (t/encode))]
(jwe/encrypt payload tokens-key {:alg :a256kw :enc :a256gcm}))) (jwe/encrypt payload tokens-key {:alg :a256kw :enc :a256gcm :header header}))))
(defn decode-header
[token]
(ex/ignoring
(jwe/decode-header token)))
(defn decode (defn decode
[{:keys [::setup/props] :as cfg} token] [{:keys [::setup/props] :as cfg} token]