Skip to content

Commit

Permalink
Add error handler for missing auth code
Browse files Browse the repository at this point in the history
Google's authorization code flow transitions to :redirect-uri without
an authorization code if a user cancels instead of authorizing. This
patch allows this type of response to be handled.
  • Loading branch information
liquidz committed May 10, 2020
1 parent 9189a88 commit e675909
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 6 deletions.
25 changes: 20 additions & 5 deletions src/ring/middleware/oauth2.clj
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,12 @@
refresh_token (assoc :refresh-token refresh_token)
id_token (assoc :id-token id_token))))

(defn- get-authorization-code [request]
(get-in request [:query-params "code"]))

(defn- request-params [profile request]
{:grant_type "authorization_code"
:code (get-in request [:query-params "code"])
:code (get-authorization-code request)
:redirect_uri (redirect-uri profile request)})

(defn- add-header-credentials [opts id secret]
Expand All @@ -79,16 +82,28 @@
(defn state-mismatch-handler [_]
{:status 400, :headers {}, :body "State mismatch"})

(defn no-auth-code-handler [_]
{:status 400, :headers {}, :body "No authorization code"})

(defn- make-redirect-handler [{:keys [id landing-uri] :as profile}]
(let [error-handler (:state-mismatch-handler profile state-mismatch-handler)]
(let [state-mismatch-handler (:state-mismatch-handler
profile state-mismatch-handler)
no-auth-code-handler (:no-auth-code-handler
profile no-auth-code-handler)]
(fn [{:keys [session] :or {session {}} :as request}]
(if (state-matches? request)
(cond
(not (state-matches? request))
(state-mismatch-handler request)

(nil? (get-authorization-code request))
(no-auth-code-handler request)

:else
(let [access-token (get-access-token profile request)]
(-> (resp/redirect landing-uri)
(assoc :session (-> session
(assoc-in [::access-tokens id] access-token)
(dissoc ::state)))))
(error-handler request)))))
(dissoc ::state)))))))))

(defn- assoc-access-tokens [request]
(if-let [tokens (-> request :session ::access-tokens)]
Expand Down
21 changes: 20 additions & 1 deletion test/ring/middleware/oauth2_test.clj
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@
(is (= {:status 400, :headers {}, :body "State mismatch"}
response))))

(testing "custom error"
(testing "custom state mismatched error"
(let [error {:status 400, :headers {}, :body "Error!"}
profile (assoc test-profile :state-mismatch-handler (constantly error))
handler (wrap-oauth2 token-handler {:test profile})
Expand All @@ -102,6 +102,25 @@
(is (= {:status 400, :headers {}, :body "Error!"}
response))))

(testing "no authorization code"
(let [request (-> (mock/request :get "/oauth2/test/callback")
(assoc :session {::oauth2/state "xyzxyz"})
(assoc :query-params {"state" "xyzxyz"}))
response (test-handler request)]
(is (= {:status 400, :headers {}, :body "No authorization code"}
response))))

(testing "custom no authorization code error"
(let [error {:status 400, :headers {}, :body "Error!"}
profile (assoc test-profile :no-auth-code-handler (constantly error))
handler (wrap-oauth2 token-handler {:test profile})
request (-> (mock/request :get "/oauth2/test/callback")
(assoc :session {::oauth2/state "xyzxyz"})
(assoc :query-params {"state" "xyzxyz"}))
response (handler request)]
(is (= {:status 400, :headers {}, :body "Error!"}
response))))

(testing "absolute redirect uri"
(let [profile (assoc test-profile
:redirect-uri
Expand Down

0 comments on commit e675909

Please sign in to comment.