Fork me on GitHub
#architecture
<
2020-02-04
>
mathpunk17:02:22

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.

mathpunk17:02:09

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

mathpunk17:02:26

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

mathpunk17:02:38

(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 "" {:cookie-store cookies})

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

(client/post "" {:cookie-store cookies
                                                              :headers {"X-XSRF-TOKEN" token-value}
                                                              :form-params {"username" ""
                                                                            "password" "s3cr3t!

(client/get "" {:cookie-store cookies})
;; => a correct-looking response

mathpunk17:02:49

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?

robertfw18:02:28

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?

robertfw18:02:39

I would probably start with writing a small wrapper (defn call-my-api [cookie-store & 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

4
robertfw18:02:06

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

robertfw18:02:19

but that would be my first general approach

lukasz18:02:53

Does the cookie expire? (I assume it does)

lukasz18:02:44

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.

mathpunk18:02:59

> 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

mathpunk18:02:46

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

mathpunk18:02:19

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

mathpunk18:02:50

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

Jakub Holý (HolyJak)16:02:02

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

robertfw23:02:08

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

robertfw23:02:34

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