From a5325a676dc5739c1a1f956256a2addb4706c189 Mon Sep 17 00:00:00 2001 From: Esko Luontola Date: Sat, 24 Feb 2024 14:51:28 +0200 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Logout=20handler?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Why: - We want to migrate from SPA to SSR. The authentication is currently done using Auth0's JavaScript libraries, but in the future it'll need to be done server-side. - With the SPA UI, we only cleared the application session but forgot to clear the Auth0 session. This time that is done properly, so that on relogin the user has an option of logging with a different account, instead of automatically reusing the Auth0 session. --- src/territory_bro/infra/auth0.clj | 22 ++++++++++++++++------ test/territory_bro/infra/auth0_test.clj | 21 +++++++++++++++++++++ 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/src/territory_bro/infra/auth0.clj b/src/territory_bro/infra/auth0.clj index c0c87ccf..39da9577 100644 --- a/src/territory_bro/infra/auth0.clj +++ b/src/territory_bro/infra/auth0.clj @@ -16,6 +16,7 @@ [territory-bro.infra.util :as util] [territory-bro.infra.util :refer [getx]]) (:import (com.auth0 AuthenticationController IdentityVerificationException) + (com.auth0.client.auth AuthAPI) (com.auth0.jwk JwkProviderBuilder) (com.auth0.jwt JWT) (java.net URL) @@ -89,10 +90,12 @@ (swap! *response response/update-header name concat (list value))))] [servlet-request servlet-response *response])) +(defn public-url [] + (-> (getx config/env :public-url) + (str/replace "8080" "8081"))) ; TODO: remove me + (defn login-handler [ring-request] - (let [public-url (-> (getx config/env :public-url) - (str/replace "8080" "8081")) ; TODO: remove me - callback-url (str public-url "/login-callback") + (let [callback-url (str (public-url) "/login-callback") [servlet-request servlet-response *ring-response] (ring->servlet ring-request) authorize-url (-> (.buildAuthorizeUrl auth-controller servlet-request servlet-response callback-url) (.withScope "openid email profile") @@ -122,6 +125,13 @@ ;; TODO: html error page (http-response/forbidden "Login failed")))) -(defn logout-handler [ring-request] - ;; TODO - (response/response "TODO")) +(defn logout-handler [_ring-request] + (let [domain (getx config/env :auth0-domain) + client-id (getx config/env :auth0-client-id) + client-secret (getx config/env :auth0-client-secret) + api (AuthAPI. domain client-id client-secret) + return-to-url (str (public-url) "/") + logout-url (-> (.logoutUrl api return-to-url true) + (.build))] + (-> (response/redirect logout-url :see-other) + (assoc :session nil)))) diff --git a/test/territory_bro/infra/auth0_test.clj b/test/territory_bro/infra/auth0_test.clj index fa64db48..8db200ff 100644 --- a/test/territory_bro/infra/auth0_test.clj +++ b/test/territory_bro/infra/auth0_test.clj @@ -101,6 +101,27 @@ :body "Login failed"} response))))))) + +(deftest logout-handler-test + (let [request {:request-method :get + :uri "/logout" + :headers {} + :session {::auth/user {:user/id (UUID. 0 1)}}} + response (auth0/logout-handler request)] + + (testing "clears the application session" + (is (= {:session nil} + (select-keys response [:session])))) + + (testing "redirects to the OIDC logout endpoint, to log out of Auth0, and then return to application home page" + ;; See https://auth0.com/docs/authenticate/login/logout + ;; https://auth0.com/docs/authenticate/login/logout/log-users-out-of-auth0 + ;; https://auth0.com/docs/api/authentication#oidc-logout + (is (= {:status 303 + :headers {"Location" "https://luontola.eu.auth0.com/v2/logout?returnTo=http://localhost:8081/&client_id=8tVkdfnw8ynZ6rXNndD6eZ6ErsHdIgPi"}} + (select-keys response [:status :headers])))))) + + (deftest ring->servlet-test (testing "request URL" ;; Servlet spec: The returned URL contains a protocol, server name, port number,