diff --git a/README.md b/README.md index 127495a..b83f09a 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,18 @@ These are URLs provided by the third-party website. If you look at the OAuth documentation for the site you're authenticating against, it should tell you which URLs to use. +Note: If you need to construct the URI at runtime, you can also configure a function +instead of a string for these parameters: + +```clojure +{:authorize-uri (fn [profile request] + ;; return a URI + ) + :access-token-uri (fn [profile request] + ;; return a URI + )} +``` + Next is the client ID and secret: * `:client-id` diff --git a/src/ring/middleware/oauth2.clj b/src/ring/middleware/oauth2.clj index 1cfe870..a5be812 100644 --- a/src/ring/middleware/oauth2.clj +++ b/src/ring/middleware/oauth2.clj @@ -17,13 +17,16 @@ (str/join " " (map name (:scopes profile)))) (defn- authorize-uri [profile request state] - (str (:authorize-uri profile) - (if (.contains ^String (:authorize-uri profile) "?") "&" "?") - (codec/form-encode {:response_type "code" - :client_id (:client-id profile) - :redirect_uri (redirect-uri profile request) - :scope (scopes profile) - :state state}))) + (let [auth-uri (if (string? (:authorize-uri profile)) + (:authorize-uri profile) + ((:authorize-uri profile) profile request))] + (str auth-uri + (if (.contains ^String auth-uri "?") "&" "?") + (codec/form-encode {:response_type "code" + :client_id (:client-id profile) + :redirect_uri (redirect-uri profile request) + :scope (scopes profile) + :state state})))) (defn- random-state [] (-> (random/base64 9) (str/replace "+" "-") (str/replace "/" "_"))) @@ -74,11 +77,14 @@ [{:keys [access-token-uri client-id client-secret basic-auth?] :or {basic-auth? false} :as profile} request] (format-access-token - (http/post access-token-uri - (cond-> {:accept :json, :as :json, - :form-params (request-params profile request)} - basic-auth? (add-header-credentials client-id client-secret) - (not basic-auth?) (add-form-credentials client-id client-secret))))) + (http/post + (if (string? access-token-uri) + access-token-uri + (access-token-uri profile request)) + (cond-> {:accept :json, :as :json, + :form-params (request-params profile request)} + 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"}) diff --git a/test/ring/middleware/oauth2_test.clj b/test/ring/middleware/oauth2_test.clj index 033cb87..06675f6 100644 --- a/test/ring/middleware/oauth2_test.clj +++ b/test/ring/middleware/oauth2_test.clj @@ -56,6 +56,16 @@ location (get-in response [:headers "Location"])] (is (.startsWith ^String location "https://example.com/oauth2/authorize?business_partner_id=XXXX&")))) +(deftest test-authorize-uri-as-a-function + (let [profile (assoc test-profile + :authorize-uri + (fn [profile request state] + "https://mycustom-url.example.com/oauth2/authorize")) + handler (wrap-oauth2 token-handler {:test profile}) + response (handler (mock/request :get "/oauth2/test")) + location (get-in response [:headers "Location"])] + (is (.startsWith ^String location "https://mycustom-url.example.com/oauth2/authorize")))) + (def token-response {:status 200 :headers {"Content-Type" "application/json"}