Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement both synchronous (1-arity) and async (3-arity) Ring handler fns #54 #55

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,28 @@ and complete authentication of the user.

[the specification]: https://tools.ietf.org/html/rfc6749#section-2.3.1

### Custom error handlers

You can override the default error handlers by providing the appropriate
keys in a profile:
```clojure
(wrap-oauth2
routes
{:github
{...
:no-auth-code-handler my-no-auth-code-handler
:state-mismatch-handler my-state-mistmatch-handler}})
```
Note that your handlers must offer the correct function arity
whether Ring and your HTTP server are being run in synchronous (1-arity)
or asynchronous (3-arity) mode.

### Synchronous and async Ring

This middleware supports both synchronous mode (1-arity Ring handler
functions) and asynchronous mode (3-arity).
However, the implementation is currently synchronous by nature.

### PKCE

Some OAuth providers require an additional step called *Proof Key for
Expand Down
43 changes: 28 additions & 15 deletions src/ring/middleware/oauth2.clj
Original file line number Diff line number Diff line change
Expand Up @@ -117,17 +117,25 @@
basic-auth? (add-header-credentials client-id client-secret)
(not basic-auth?) (add-form-credentials client-id client-secret)))))

(defn state-mismatch-handler [_]
{:status 400, :headers {}, :body "State mismatch"})
(defn- make-error-response-handler-fn [message]
(let [response {:status 400
:headers {}
:body message}]
(fn
([_request] response)
([_request respond _raise] (respond response)))))

(defn no-auth-code-handler [_]
{:status 400, :headers {}, :body "No authorization code"})
(def default-state-mismatch-handler
(make-error-response-handler-fn "State mismatch"))

(def default-no-auth-code-handler
(make-error-response-handler-fn "No authorization code"))

(defn- make-redirect-handler [{:keys [id landing-uri] :as profile}]
(let [state-mismatch-handler (:state-mismatch-handler
profile state-mismatch-handler)
no-auth-code-handler (:no-auth-code-handler
profile no-auth-code-handler)]
(let [state-mismatch-handler (get profile :state-mismatch-handler
default-state-mismatch-handler)
no-auth-code-handler (get profile :no-auth-code-handler
default-no-auth-code-handler)]
(fn [{:keys [session] :or {session {}} :as request}]
(cond
(not (state-matches? request))
Expand Down Expand Up @@ -158,10 +166,15 @@
{:pre [(every? valid-profile? (vals profiles))]}
(let [profiles (for [[k v] profiles] (assoc v :id k))
launches (into {} (map (juxt :launch-uri identity)) profiles)
redirects (into {} (map (juxt parse-redirect-url identity)) profiles)]
(fn [{:keys [uri] :as request}]
(if-let [profile (launches uri)]
((make-launch-handler profile) request)
(if-let [profile (redirects uri)]
((:redirect-handler profile (make-redirect-handler profile)) request)
(handler (assoc-access-tokens request)))))))
redirects (into {} (map (juxt parse-redirect-url identity)) profiles)
f (fn [{:keys [uri] :as request}]
(if-let [profile (launches uri)]
((make-launch-handler profile) request)
(if-let [profile (redirects uri)]
((:redirect-handler profile
(make-redirect-handler profile))
request)
(handler (assoc-access-tokens request)))))]
(fn
([request] (f request))
([request respond _] (respond (f request))))))
Loading