Skip to content

Instantly share code, notes, and snippets.

@stijnopheide
Created January 21, 2019 13:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stijnopheide/af90400b26a686e1145b9a5e2f0a2874 to your computer and use it in GitHub Desktop.
Save stijnopheide/af90400b26a686e1145b9a5e2f0a2874 to your computer and use it in GitHub Desktop.
yada + lacinia + cookie auth
(def cookie-authentication
{:realm realm
:authentication-schemes [{:verify (fn [{:keys [:my/db cookies] :as ctx}]
(when-let [session-cookie (get cookies session-cookie-name)]
(verify-session db session-cookie)))}]})
(defn add-session-cookie
[defaults]
(fn [{:keys [::session] :as ctx}]
(if session
(assoc-in ctx [:response :cookies session-cookie-name] (create-session-cookie defaults session))
ctx)))
(defn cors-access-control
[{:keys [allow-origin]} methods]
{:allow-headers #{"Content-Type"}
:allow-credentials true
:expose-headers #{}
:allow-methods methods
:allow-origin (cond
(string? allow-origin)
(fn [{:keys [request] :as ctx}]
(when-let [origin (get-in request [:headers "origin"])]
(when (re-find (re-pattern allow-origin) origin)
origin)))
:else allow-origin)})
(defn execute-query
[ctx variables parsed-query]
(let [resolver-result (lacinia/execute-parsed-query-async parsed-query variables ctx)
result (md/deferred)]
(lacinia.resolve/on-deliver! resolver-result
(fn [x]
(md/success! result x)))
result))
(defn execute-query-and-create-response
[ctx schema query variables operation-name]
(md/let-flow [parsed-query (parse-query schema query operation-name)]
(execute-query ctx variables parsed-query)))
(defn parse-query-from-json
[ctx]
[(get-in ctx [:parameters :body :query])
(get-in ctx [:parameters :body :variables])
(get-in ctx [:parameters :body :operationName])])
(defn graphql-resource
[schema auth]
(yada/resource
{:produces
#{"application/json"}
:methods
{:post
{:parameters {:body s/Any
:query {(s/optional-key :variables) String
(s/optional-key :query) String
(s/optional-key :operationName) String}}
:produces #{"application/json" "application/json; charset=utf-8"}
:consumes #{"application/json" "application/graphql"}
:response (fn [ctx]
(let [[query variables operation-name]
(case (get-in ctx [:request :headers "content-type"])
"application/json" (parse-query-from-json ctx)
"application/json; charset=utf-8" (parse-query-from-json ctx)
"application/graphql" [(or (get-in ctx [:parameters :query :query])
(get-in ctx [:parameters :body]))
(json/parse-string (get-in ctx [:parameters :query :variables]) true)
(get-in ctx [:parameters :query :operationName])])]
(execute-query-and-create-response ctx schema query variables operation-name)))}
:get
{:parameters {:query {:query String
(s/optional-key :variables) String
(s/optional-key :operationName) String}}
:response (fn [ctx]
(execute-query-and-create-response ctx
schema
(get-in ctx [:parameters :query :query])
(json/parse-string (get-in ctx [:parameters :query :variables]) true)
(get-in ctx [:parameters :query :operationName])))}}
:access-control
(merge (ors-access-control (:cors auth) #{:post :get})
cookie-authentication)
:interceptor-chain
(-> yada/default-interceptor-chain
(util.yada/insert-interceptor
yada.interceptors/create-response
(add-session-cookie (:session-cookie auth))))
:responses
responses}))
(defn login-response
[ctx [session cookies]]
(assoc (:response ctx)
:body (whatever-you-need-from session)
:cookies cookies))
(defn login
[auth]
(yada/resource
{:methods
{:post {:parameters {:body {:token String}}
:response (fn [ctx]
(md/chain (do-your-login-with-whatever-you-need-from-the-request-and-give-back-a-session-cookie (get-in ctx [:parameters]))
(fn [result]
(login-response ctx result))))
:produces #{"application/json"}
:consumes #{"application/json"}}}
:access-control
(auth/cors-access-control (:cors auth) #{:post})
:responses
responses}))
(defn routes
[auth]
[""
[["/login" (login auth)] ;; some resource that sets the cookies properly
["/graphiql" (yada.resources.classpath-resource/new-classpath-resource "public/graphiql" ;; graphiql downloaded and installed in resource folder
["/graphql" (graphql-resource graphql auth)]]])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment