biff

Oleksii Koval 2025-01-19T19:41:17.920889Z

Can I ask some novice questions here? For example: I would like to configure oauth2 for my application, trying to follow docs on https://github.com/weavejester/ring-oauth2 So far I managed to understand that: • this middleware needs to be placed after biff/wrap-session so it can store & verify the state code security check • this middleware needs to be placed after wrap-params middleware to be able to read & compare GET parameters But my limited experience with Clojure development is not enough yet to understand the best placement & middleware layout After some experimenting, this seems to work:

(defn wrap-base-defaults [handler]
  (-> handler
      (wrap-oauth2 (oauth-config))
      wrap-params
      biff/wrap-session
      muuntaja/wrap-params
      biff/wrap-https-scheme
      biff/wrap-resource
      biff/wrap-internal-error
      biff/wrap-ssl
      biff/wrap-log-requests
))
but I have some doubts

Oleksii Koval 2025-01-19T19:59:00.252099Z

btw I also need to pass config data in my (oauth-config) function. this is unresolved yet (hardcoded for the testing time, but needs to be read from aero-config)

2025-01-21T00:35:08.086879Z

If it needs to run after wrap-session and wrap-params, you could insert it into wrap-site-defaults , like:

(defn wrap-site-defaults [handler]
  (-> handler
      biff/wrap-render-rum
      biff/wrap-anti-forgery-websockets
      csrf/wrap-anti-forgery
      (wrap-oauth2 (oauth-config))
      biff/wrap-session
      muuntaja/wrap-params
      muuntaja/wrap-format
      (rd/wrap-defaults (-> rd/site-defaults
                            (assoc-in [:security :anti-forgery] false)
                            (assoc-in [:responses :absolute-redirects] true)
                            (assoc :session false)
                            (assoc :static false)))))
(note that since we're composing the middleware with ->, middleware that comes earlier in the chain runs last) The downside of the code snippet you posted (moving wrap-session etc into wrap-base-defaults ) is that wrap-base-defaults gets used for both :routes and :api-routes in your Biff modules. If you ever start using :api-routes , you probably won't want to have it use wrap-session. > btw I also need to pass config data in my (oauth-config) function. this is unresolved yet (hardcoded for the testing time, but needs to be read from aero-config) The way to do this in Biff is somewhat peculiar: you'll need to make a wrapper middleware that doesn't need any config at "wrap" time, but on each request, it'll take the config from the incoming request / ctx and then pass it to the original oauth2 middleware:
(defn my-wrap-oauth2 [base-handler]
  (fn [ctx]
    (let [config (get-oauth-config ctx)
          handler (wrap-oauth2 base-handler config)]
      (handler ctx))))
I've set things up this way so that the middleware chain can be constructed/updated at the repl without having to refresh the whole system, i.e. just hit save and everything's up to date. The biff/wrap-session middleware does the same thing; it's mostly just a wrapper like the one above: https://github.com/jacobobryant/biff/blob/94eb24d96b0592399f264e1ee2ffeab186f46c78/src/com/biffweb/impl/middleware.clj#L115

❤️ 1