Note that there are some explanatory texts on larger screens.

plurals
  1. POUse Friend for authentication and authorisation in a single page Clojure web application
    primarykey
    data
    text
    <p>I am trying to integrate Friend authentication and authorisation into a Clojure/Compojure single-page web application.</p> <p>I have a login form backed by an Angular controller, and this controller uses AJAX to authenticate username and password against the web application and obtain an authenticated user record. Because of this, I do not want the default behaviour provided by the Friend form-based login - I basically want to rely on HTTP status codes and I do <em>not</em> want any of the Friend page-redirects.</p> <p>For example, making an unauthenticated request should simply return a 401 status code, and should not redirect to "/login". I have this part working by specifying a custom ":unauthenticated-handler" when configuring Friend (code included below).</p> <p>On a successful login I simply want a 200 status code, and not a redirect to the originally requested page. This is what I can't get working.</p> <p>I wrote a custom Friend authentication workflow based on the various examples (my Clojure skills are beginner level right now):</p> <pre><code>(defn my-auth [&amp; {:keys [credential-fn]}] (routes (GET "/logout" req (friend/logout* {:status 200})) (POST "/login" {{:keys [username password]} :params} (if-let [user-record (-&gt; username credential-fn)] (if (and [user-record password] (creds/bcrypt-verify password (:password user-record))) (let [user-record (dissoc user-record :password)] (workflows/make-auth user-record {:cemerick.friend/workflow :my-auth :cemerick.friend/redirect-on-auth? true})) {:status 401}) {:status 401})))) </code></pre> <p>Here is my handler with middlewares declared:</p> <pre><code>(def app (-&gt; (handler/site (friend/authenticate app-routes {:credential-fn (partial creds/bcrypt-credential-fn my-credential-fn) :unauthenticated-handler unauthenticated :workflows [(my-auth :credential-fn my-credential-fn)]})) (session/wrap-session) (params/wrap-keyword-params) (json/wrap-json-body) (json/wrap-json-response {:pretty true}))) </code></pre> <p>And the additional handler function referenced by the above:</p> <pre><code>(defn unauthenticated [v] {:status 401 :body "Unauthenticated"}) </code></pre> <p>Finally an additional routes fragment to test the authentication:</p> <pre><code>(GET "/auth" req (friend/authenticated (str "You have successfully authenticated as " (friend/current-authentication)))) </code></pre> <p>This <em>mostly</em> works, and <em>almost</em> does everything I need.</p> <p>Because "redirect-on-auth?" is true in "make-auth", on a successful login a page-redirect is generated - I want to prevent that redirect so I set the value to false. However, this single change results in a 404 and a failed login.</p> <p>So as well as the Friend authentication map I need somehow to return a 200 status code here, and also I want to return the "user-record" in the response body so the client application can tailor the UI depending on the user roles (I already have JSON requests/responses wrapped and working).</p> <p>So I think I need the equivalent of this when I invoke the Friend "make-auth" function:</p> <pre><code>{:status 200 :body user-record} </code></pre> <p>However it seems like I can have either the authentication map, or the response - but not both together.</p> <p>Can this be achieved with Friend and if so how?</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload