     (-handle-unauthorized [_ request errordata]
       (callable request errordata))))
 
+(defn authorization-error
+  "Handles authorization errors.
+
+  The `backend` parameter should be a plain function
+  that accepts two parameters: request and errordata hashmap,
+  or an instance that satisfies IAuthorization protocol."
+  [request e backend]
+  (let [backend (cond
+                  (fn? backend)
+                  (fn->authorization-backend backend)
+
+                  (satisfies? proto/IAuthorization backend)
+                  backend)]
+    (if (instance? clojure.lang.ExceptionInfo e)
+      (let [data (ex-data e)]
+        (if (= (:buddy.auth/type data) :buddy.auth/unauthorized)
+          (->> (:buddy.auth/payload data)
+               (proto/-handle-unauthorized backend request))
+          (throw e)))
+      (if (satisfies? proto/IAuthorizationdError e)
+        (->> (proto/-get-error-data e)
+             (proto/-handle-unauthorized backend request))
+        (throw e)))))
+
 (defn wrap-authorization
   "Ring middleware that enables authorization
   workflow for your ring handler.

;; Authentication
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defn wrap-authentication
  "Ring middleware that enables authentication for your ring
  handler. When multiple `backends` are given each of them gets a
  chance to authenticate the request."
  [handler & backends]
  (fn [request]
    (let [authdata (loop [[backend & backends] backends]
                     (when backend
                       (let [request (assoc request :auth-backend backend)]
                         (or (some->> request
                                      (proto/-parse backend)
                                      (proto/-authenticate backend request))
                             (recur backends)))))]
      (handler (assoc request :identity authdata)))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Authorization

  hashmap, or an instance that satisfies IAuthorization
  protocol."
  [handler backend]
  (fn [request]
    (try (handler request)
         (catch Exception e
           (authorization-error request e backend)))))
