2

This is my client side code. I'm using cljs-ajax for POST

(defn persist-state []
  (POST "/save" {:params {:state @state}))

Here is my server side code to handle the POST. I'm using compojure.

(POST "/save" req
      (let [state (:state (req :params))]
           (add-state! state)
           {:status 200}))

When I trigger the ajax POST it gives a 403 forbidden error. How do I get around this? Couldn't find anything online to help me.

Edit: My middleware looks like this

(def app                                                                        
  (let [handler (wrap-defaults #'routes site-defaults)]                         
    (if (env :dev) (-> handler wrap-exceptions wrap-reload) handler)))

This was generated from the lein reagent template. I'm fairly certain my problem is related to not setting anti-forgery token.

1 Answers1

4

There are two basic ways to solve your problem. Which suits depends on your app and what you want.

Option 1. If you do not want the CSRF protection, you can turn it off. To do this, you can either disable it by changing the site-defaults map or you could use api-defaults instead of site defaults (which has the csrf support disabled by default). To turn it off, you could do something like

(let [handler (wrap-defaults #'routes (assoc-in site-defaults [security :anti-forgery] false))]  
  .....)

Option 2. You need to get the server to send the current token to your client. With static forms, this is normally done by putting the token in a hidden field within the form. An alternative iuseful for dynamic content where you use javascript is to have the server generate an initial page which sets a js variable with the token in it.

The Luminus template has quite a nice example of how you can handle these tokens in a flexible manner. It uses the Selmar package for templates and adds a new template tag that represents the csrf token.

Tim X
  • 4,158
  • 1
  • 20
  • 26