Fork me on GitHub

I have a route path that should support both get and delete http methods. Thing is if I put it under :routes, GET works but not DELETE (I'm getting a 403). I definitely don't want to put :delete under api-routes because I need CSRF protection. I believe I need to set up CORS for htmx: but I'm not sure that's it or how to do it. My routes (simplified) in ๐Ÿงต


(def features
  {:routes ["/app" {:middleware [anti-forgery/wrap-anti-forgery
                                  :access-control-allow-origin #".*"
                                  :access-control-allow-methods [:delete]]]}
            ["/match/:match-id" {:get (partial app-wrapper match)
                                 :delete match-delete}]
            ["/settings" {:get (partial app-wrapper settings)}]]})
/app/settings contains two buttons. One makes an htmx call to GET /app/match/:match-id and another to DELETE /app/match/:match-id. The former works but not the latter


It doesn't make any difference whether I include the wrap-cors middleware or not

Jacob O'Bryant08:01:26

the htmx request probably isn't including the csrf token. if the request happens inside of a (biff/form ...) then the token should get included, but in other cases you need to do more stuff to include the token. you can check the request headers/form parameters to see if the token is there. here's an example from the tutorial: I've been thinking I should make biff do that by default

๐Ÿ™ 2

Not on my machine now but from the sounds of it I'm pretty sure that's it. The request doesn't come from a form and I didn't realize I had to add the headers explicitly


Why does it only happen with delete though?

Epidiah Ravachol15:01:06

I believe GET requests don't require a csrf token because they shouldn't be changing anything in your database.

โ˜๏ธ 2

Right, that's what I thought, thanks for confirming, but who decides whether a csrf token is necessary? Is this a web server (e.g. jetty) or a browser thing (i.e. web standard)?

Epidiah Ravachol15:01:37

Ooh, that's a good question. It looks like the Ring anti-forgery middleware that Biff wraps all the non-`api-routes` in is doing the checking: In fact, in addition to GET requests, it lets HEAD and OPTIONS requests through, too:

(defn- get-request? [{method :request-method}]
  (or (= method :head)
      (= method :get)
      (= method :options)))

(defn- valid-request? [strategy request read-token]
  (or (get-request? request)
      (when-let [token (read-token request)]
        (strategy/valid-token? strategy request token))))

โ˜๏ธ 2
๐Ÿ™ 2