Fork me on GitHub
#luminus
<
2018-04-29
>
clojer18:04:15

I’m having trouble grokking REACT API authentication as explained here: http://www.luminusweb.net/docs/services.html. The Authentication section is cursory and involves 2 “restructure-params” defmethods without a corresponding defmulti. This kind of high magic without basic explanation just feeds the commonly-held view that Clojure is for experts.

clojer18:04:32

Is there a simpler explanation of how this works? It seems I can’t avoid using this code if I need to implement a REST API in Luminus.

eoliphant18:04:32

Hi @clojer, just quickly, if you’re coming from say Java/Ruby/etc worlds, like id did. Yes it can be a bit different and not immediately obvious, especially given that in clojureworld, there’s more focus on libraries v frameworks, so luminus is a approach that wires some ‘curated’ set of libraries up for you. For your specific question, what’s happening there is a combination of ring middleware that actually handles the authentication, that could be pulling the id off of a JWT, or per the example, pulling it from the session,etc. Then, in order to use features of the api library (compojure-api), like providing the current user , issuing an unauthorized, etc) the restructure-param calls defining a mapping from the middleware (defined in middleware.clj in a generated project) to the api. Such that say current-user is resolved correctly. To fully understand this, you’ll need to peruse the ring and compojure-api docs. But if you’ve used the appropriate luminus options when you create your project, it should pretty much work out of the box, or with slight modifications, depending on your requirements. For instance, for some of my projects I use the Auth0 third-party authentication service, I’ve alternatively written my own, and used third-party middleware to properly decode its tokens, and made the appropriate changes to my restructure-param calls.

clojer19:04:33

I don’t see any code here which explains how to hook this all up with a database connection which verifies the username and password. So much seems to be assumed.

eoliphant19:04:58

Have you created a sample project?

clojer19:04:12

There’s conman, yes, but I don’t see how that connects with all this wrapping.

eoliphant19:04:18

That might make things clearer use say the +postgres option

clojer19:04:50

I’m using +postgres and looking to implement a simple session based auth.

eoliphant19:04:30

ok by default a database enabled luminus project is going to expose a conn component

clojer19:04:37

This is anything but simple which is what I thought Clojure was all about. “Injection” doesn’t sound very idiomatic.

clojer19:04:15

I have the conn setup and working.

eoliphant19:04:40

well, this would be more a discussion of the general software architecture, than clojure specifically. Yes you can and should do pure functions, etc to the extent possible, but you need side-effects for ‘interesting’ stuff like writing to a database. And there’s unavoidable ‘global state’ you need like database connections. libraries like mount, which luminus uses provide a way to get at those kinds of things. You should still in say your ‘user managment’ namespace make things as pure as possible, like separate code that reads/writes to the database from code that makes business decisions about users. But in this case just to get started, you just need say a couple functions, perhaps like

(ns myapp.users ..)
(defn save-user [username password conn] ...)
(defn get-user [username conn] ...)

; a 'pure' checker
(defn password-valid? [password db-password] ... do bcrypt, etc check here)
Also, a good practice is to always pass your functions what they need, so even say the side-effecting save-user above, should have it’s connection passed in where you’re calling it, as opposed to referencing directly in the namespace

sveri19:04:13

@clojer if you are interested I can link you some code, but its a bit more and not based on the luminus template.

clojer20:04:47

sveri: Yeah, would be interesting to have a look. I’m thinking maybe I can just ignore the whole restructure-param and go for something simpler?