Search code examples
clojure

clojure: No implementation of method of protocol found for class


I have a ring server. I am using Buddy for authentication / authorization. I implemented my own token backend by implementing -parse, -authenticate, and -handle-unauthorized of the buddy protocols IAuthentication and IAuthorization. Here it is:

(ns myproject.auth
  (:require [buddy.auth.protocols :as proto]))

...

(defn my-token-backend
  ([] (my-token-backend nil))
  ([{:keys [unauthorized-handler]}]
   (reify
     proto/IAuthentication
     (-parse [_ request]
       (token-or-nil))
     (-authenticate [_ request token]
       (get-user-from-token token))
     proto/IAuthorization
     (-handle-unauthorized [_ request metadata]
       (if unauthorized-handler
         (unauthorized-handler request metadata)
         (handle-unauthorized-default request))))))

I then use my backend in wrap-authentication and wrap-authorization middleware:

(defn middleware [handler]
  (-> handler
      (wrap-authentication my-token-backend)
      (wrap-authorization my-token-backend)

...and call my app with that middleware like so: (def app (middleware main-routes)).

When I go to my index page in my browser, I get the following error: java.lang.IllegalArgumentException: No implementation of method: :-parse of protocol: #'buddy.auth.protocols/IAuthentication found for class: myproject.auth$my_token_backend.

When I call (reflect my-token-backend) in the REPL, I noticed the dashes in the names of the methods -parse, -authenticate, and -handle-unauthorized have been converted to underscores. Is this why I'm getting that error, or is the error coming from somewhere else?


Edit: After Sean's comment, I've changed my middleware to look like the following:

(defn middleware [handler]
  (-> handler
      (wrap-authentication (my-token-backend))
      (wrap-authorization (my-token-backend))))

Solution

  • The class myproject.auth$my_token_backend is the function my-token-backend and the error you are getting says that the call to -parse is expecting an object that implements the protocols -- which would be the result of calling your function.

    So I think you want:

    (defn middleware [handler]
      (-> handler
          (wrap-authentication (my-token-backend))
          (wrap-authorization (my-token-backend)))