architecture

mathpunk 2020-02-04T17:36:22.003100Z

I'm talking to my company's app's api. First I need to get a session token and authenticate, then I can mess around in the repl.

mathpunk 2020-02-04T17:37:09.004100Z

I'd like to know, what is a sane way to run a function that does these things and verifies that I'm authenticated, and then stop worrying about it

mathpunk 2020-02-04T17:37:26.004500Z

here is what I ran in the repl to get authenticated and verify I'd done it right:

mathpunk 2020-02-04T17:37:38.004800Z

(ns api.auth-and-verify
  (:require [clj-http.client :as client]
            [clj-http.cookies :as cookie]
            [cheshire.core :as json]
            [slingshot.slingshot :refer [try+]]))


(def cookies (cookie/cookie-store))

(client/get "<http://localhost:8080>" {:cookie-store cookies})

(def token-value
  (get-in (cookie/get-cookies cookies) ["XSRF-TOKEN" :value]))

(client/post "<http://localhost:8080/api/v1/proxy/auth/token>" {:cookie-store cookies
                                                              :headers {"X-XSRF-TOKEN" token-value}
                                                              :form-params {"username" "<mailto:user@company.co|user@company.co>"
                                                                            "password" "s3cr3t!

(client/get "<http://localhost:8080/api/v1/internal/account/details>" {:cookie-store cookies})
;; =&gt; a correct-looking response

mathpunk 2020-02-04T17:38:49.006200Z

does anyone have recommendations on how to organize this so I can call a function once and then have future calls be more about the body of requests and less about the cookie-and-header auth plumbing?

robertfw 2020-02-04T18:35:28.008500Z

The cookie is state, so you are wanting some kind of state management - is this in the context of a larger app, or just fiddling around in the repl?

robertfw 2020-02-04T18:38:39.011300Z

I would probably start with writing a small wrapper (defn call-my-api [cookie-store &amp; args]... which you would call passing a stateful cookie store (probably just an atom if you are just doing repl work, but in the context of an app, a component or some such thing managed by component, mount, integrant etc). that function can check the state of the cookie store to see if you are authed, authenticate if not, and then pass args through to the post

➕ 1
robertfw 2020-02-04T18:40:06.012500Z

could take it in a few different directions frm there depending on the variety of calls you need to make

robertfw 2020-02-04T18:40:19.012800Z

but that would be my first general approach

lukasz 2020-02-04T18:43:53.013100Z

Does the cookie expire? (I assume it does)

lukasz 2020-02-04T18:45:44.015Z

We have somewhat similar code in one of the parts of the system which has to refresh API tokens every now and then, we do this by centralizing the token rotation and make all clients aware of the token and pulling it from a shared resource (a Component actually). This way performing requests doesn't involve refreshing the token and obtaining a new one.

mathpunk 2020-02-04T18:55:59.019500Z

> is this in the context of a larger app, or just fiddling around in the repl? Currently fiddling, but with an interest in using a programming language to do some API work and API tests in something other than Postman

mathpunk 2020-02-04T18:57:46.021400Z

Postman is familiar to the rest of my team but, from working with it this week it seems like it would be much better to just use a programming language. I developed the code above in parallel, while I was learning how auth worked at all

mathpunk 2020-02-04T18:59:19.023100Z

The cookie does expire. In my workflow, I restart our app much more often than the cookie expires. Some of the developers may have the same instance of the app running long enough for expiration to be a concern

mathpunk 2020-02-04T18:59:50.023900Z

It does sound like it's time for me to learn one of those component-style frameworks, finally

Jakub Holý 2020-02-11T16:30:02.035300Z

Try without it for a while, just making the http client call wrapper fn. There is always time to add complexity later :)

robertfw 2020-02-04T23:58:08.026100Z

yup, and you can handle the time out refreshing within that as well. when the cookie is authed for the first time, you could kick off a little core.async.go-loop that parks until you hit your timeout threshold, refreshes the token, then loops. for a little more resiliancy you may need to add a little bit of mechanism to hold off on making a call if you are currently refreshing the auth token, so you don't try to send a request at the same time

robertfw 2020-02-04T23:59:34.027600Z

i'm using stuartsierra.component currently but I've heard nothing but good things about integrant, I've been meaning to try it out on a new project for a while. I'd probably start by looking at integrant as it was built largely in response to some common complaints about component