3
votes

We have a web application that uses HttpKit to serve requests and a handler wrapped with Ring middleware.

The handler is similar to:

(def handler
  (->  #'req-handler
    (wrap-defaults site-defaults)
    (wrap-content-type-and-encoding)
    (wrap-cookies)
    (wrap-stacktrace)))

In the site-defaults one can find:

 :security  { ...
              :anti-forgery         anti-forgery-setting
              ... }

The application used to serve only requests coming from browsers, but now some of the endpoints respond to API requests, POST operations included.

In the documentation I can read:

This middleware will prevent all HTTP methods except for GET and HEAD from accessing your handler without a valid anti-forgery token.

You should therefore only apply this middleware to the parts of your application designed to be accessed through a web browser. This middleware should not be applied to handlers that define web services.

Is there any way to apply the anti-forgery setting conditionally, or give a different version of the site-defaults depending on the request?.

1
there's a set of api-defaults in ring you can use for routes leading to your API endpointsJochen Bedersdorfer

1 Answers

4
votes

You can use ring.middleware.conditional's operators to conditionally add middleware. For example, to conditionally add the api-defaults mentioned in the comment of Jochen Bedersdorfer:


(require '[ring.middleware.conditional :as middleware.conditional]
(require '[ring.middleware.defaults :refer [api-defaults site-defaults])

(defn wrap-api-defaults [handler]
  (wrap-defaults handler api-defaults))

(defn wrap-site-defaults [handler]
  (wrap-defaults handler site-defaults))

(def handler
  (-> #'req-handler
      (middleware.conditional/if-url-starts-with "/api" wrap-api-defaults)
      (middleware.conditional/if-url-doesnt-start-with "/api" wrap-site-defaults)
      (wrap-content-type-and-encoding)
      (wrap-cookies)
      (wrap-stacktrace)))