Fork me on GitHub

What is the best way to secure Pedestal REST-endpoints?


@skylar: I haven't gotten to using it yet, but has been recommended to me when I asked about it earlier.


Are there any examples of how to use the resource ring-middleware ( or any of the other ring-middleware that takes an argument? It's just different enough from the examples I can find (for both ring and pedestal) that it's giving me a bit of difficulty figuring out. I think I'm almost there but not sure yet if what I'm trying is just a terrible mess compared to what it could be.


@shaun-mahood, the ring resource middleware is used when :io.pedestal.http/resource-path is set on the service-map. Refer to All the middleware adapters in the io.pedestal.http.ring-middlewares namespace are just functions which return interceptors. To use them, you would invoke the functions when building your interceptor chain. A lot of them are configured through the default-interceptors fn, though. Take a deeper look there for more details.


@skylar another authentication option is Buddy ( There’s a PR which includes an a Buddy auth integration sample project.


@ddeaguiar: Maybe I'm going down the wrong path then - what I'm trying to do is grab a file from the local filesystem (not in the resource-path) and serve that file. My thought was that I could use one of the existing ring-middlewares and pass in the specific file path. At this point I've got an interceptor that grabs the info from the request and does a query to find the file-path and adds that to the context, and I want to have that file-path sent to the resource middleware (or one of the alternatives) - so for now I'm trying to just wrap it with another interceptor that passes in the file-path. My first thought was to just put the argument (or the path to the context) into the interceptor chain directly, but I couldn't find a way to do that. What you posted above helps since I was making one wrong assumption already, so thanks!


Harumph... the war example seems broken....


any ideas on how to poke at this one?


@bherrmann I'll take a look at this. I've needed to understand how war deployment works for a while. (I never worked on that part before.) What I see at the moment looks like a missing Jar file for the servlet API.


@bherrmann OK, I figured out what was going on. In the war example, we don't have Jetty in the dependencies. That's so the war file doesn't contain a complete copy of Jetty, Tomcat, etc.


Instead, there's a profile in project.clj that you need to add for REPL based development only.


So if you run 'lein with-profile +jetty repl' you get the desired behavior.


I've pushed an update to the readme that clarifies this process.


As an aside, one thing I'd really love to have is build automation that could start up and test each of the samples during a CI build...


   #{["/" :get (fn [_] {:status 200 :body "Hello"}) :route-name :main]}) :main)
ExceptionInfo Route not found clojure.core/ex-info (core.clj:4617) I'm missing something?


@souenzzo I think form-action-for-routes needs the fully-expanded routes. Can you try the same thing with the value of (:io.pedestal.http/routes service-map) after starting the service?


(let [routes #{["/" :get (fn [_] {:status 200 :body "Hello"}) :route-name :main]}
      service {::bootstrap/routes routes
               ::bootstrap/join?  false
               ::bootstrap/type   :jetty
               ::bootstrap/port   8080}
      server (bootstrap/create-server service)]
  ((io.pedestal.http.route/form-action-for-routes (::bootstrap/routes server)) :main))

ExceptionInfo Route not found  clojure.core/ex-info (core.clj:4617)


#error{:cause "Route not found",
       :data {:app-name nil, :route-name :main},
       :via [{:type clojure.lang.ExceptionInfo,
              :message "Route not found",
              :data {:app-name nil, :route-name :main},
              :at [clojure.core$ex_info invokeStatic "core.clj" 4617]}],
       :trace [[clojure.core$ex_info invokeStatic "core.clj" 4617]
               [clojure.core$ex_info invoke "core.clj" 4617]
               [io.pedestal.http.route$find_route invokeStatic "route.clj" 265]
               [io.pedestal.http.route$find_route invoke "route.clj" 259]
               [io.pedestal.http.route$form_action_for_routes$fn__10117 doInvoke "route.clj" 495]
               [clojure.lang.RestFn invoke "" 410]
               [formiguinhas_service.service$eval69611 invokeStatic "form-init7223753487312925116.clj" 8]
               [formiguinhas_service.service$eval69611 invoke "form-init7223753487312925116.clj" 1]
               [clojure.lang.Compiler eval "" 6927]
               [clojure.lang.Compiler eval "" 6890]
               [clojure.core$eval invokeStatic "core.clj" 3105]
               [clojure.core$eval invoke "core.clj" 3101]
               [clojure.main$repl$read_eval_print__7408$fn__7411 invoke "main.clj" 240]
               [clojure.main$repl$read_eval_print__7408 invoke "main.clj" 240]
               [clojure.main$repl$fn__7417 invoke "main.clj" 258]
               [clojure.main$repl invokeStatic "main.clj" 258]
               [clojure.main$repl doInvoke "main.clj" 174]
               [clojure.lang.RestFn invoke "" 1523]
               [$evaluate$fn__68771 invoke "interruptible_eval.clj" 87]
               [clojure.lang.AFn applyToHelper "" 152]
               [clojure.lang.AFn applyTo "" 144]
               [clojure.core$apply invokeStatic "core.clj" 646]
               [clojure.core$with_bindings_STAR_ invokeStatic "core.clj" 1881]
               [clojure.core$with_bindings_STAR_ doInvoke "core.clj" 1881]
               [clojure.lang.RestFn invoke "" 425]
               [$evaluate invokeStatic "interruptible_eval.clj" 85]
               [$evaluate invoke "interruptible_eval.clj" 55]
               [clojure.lang.AFn run "" 22]
               [java.util.concurrent.ThreadPoolExecutor runWorker "" 1142]
               [java.util.concurrent.ThreadPoolExecutor$Worker run "" 617]
               [java.lang.Thread run "" 748]]}


Even after (-> service bootstrap/default-interceptors bootstrap/create-server bootstrap/start), the routes continue as a set


@souenzzo I have to head out for dinner. I'll check back in later. Let me know if that doesn't work and I can dig some more.


@mtnygard I still cant use form-action-for-routes 😕


OK, I'll try to diagnose further later.


@mtnygard Huh. While you looked at that, I was writting up this,


@mtnygard Your "lein with-profile +jetty repl" does work for the REPL case though.


I wonder if using a WAR file is just weird. It doesnt appear to be the path most traveled.