oliyh / martian

The HTTP abstraction library for Clojure/script, supporting OpenAPI, Swagger, Schema, re-frame and more
MIT License
525 stars 42 forks source link

Interceptors for session authentication #162

Closed michaelwhitford closed 1 year ago

michaelwhitford commented 1 year ago

I have an api that requires a session id header. You post a basic auth into /api/session and it returns a session id. Then further requests to other api endpoints need that session id as a header attached. I have the basic auth part working using an interceptor that adds the authorization header. I can't seem to figure out how to attach that session id header to further requests.

(def add-basic-auth-header
  {:name ::add-basic-auth-header
  :enter (fn [ctx]
                 (assoc-in ctx [:request :headers "Authorization"] "Basic base64encodedusernamepasswordhere"]))})

This interceptor works great. But how do I then use the session id in further requests? When I try to add a custom header when I call for the response it is not being added.

(def sid (:body (martian/response-for api :session)))
; sid is now a string of the session id
; this is not adding the session-id header to the request
(martian/request-for api :session {:headers {"session-id" sid})
{:method :post,
 :url "https://example.com/api/session",
 :insecure? true,
 :headers
 {"Authorization" "Basic base64encodedusernamepasswordhere",
  "Accept" "application/json"},
 :as :text}

This shows the authorization header, but not the session-id header. Looking at the code it seems this should add a header, but it is not. Is there a better way to handle this type of authentication using just interceptors?

michaelwhitford commented 1 year ago

Solved it using a custom param in the interceptor.

(def add-session-id
  {:name ::add-session-id
   :enter (fn [ctx]
                 (if-let [sid (get-in ctx [:params :session-id])]
                    (assoc-in ctx [:request :headers "session-id"] sid)
                     ctx))})
oliyh commented 1 year ago

It sounds like the session-id header was not part of the specification in the api's descriptor. Martian will discard any params you pass it that are not part of the descriptor, and I think that happened here. Your interceptor is a good workaround for this.