diff --git a/cogstack-cohorter/WebAPP/README.md b/cogstack-cohorter/WebAPP/README.md index 069f98f..20f1b52 100644 --- a/cogstack-cohorter/WebAPP/README.md +++ b/cogstack-cohorter/WebAPP/README.md @@ -73,9 +73,20 @@ These variables are only needed when **oauth2-proxy is deployed in front of the |---|---|---| | `OAUTH2_USERINFO_PATH` | `/oauth2/userinfo` | Path the `UserSection` component fetches to get the logged-in user's info. With oauth2-proxy this is intercepted by oauth2-proxy before reaching Express. Without oauth2-proxy it hits the Express fallback endpoint. | | `OAUTH2_LOGIN_PATH` | `/oauth2/sign_in` | Path the header's "Sign in" button links to | -| `OAUTH2_LOGOUT_PATH` | `/oauth2/sign_out?rd=/` | Path the header's "Sign out" button links to | +| `OAUTH2_LOGOUT_PATH` | `/logout` | Path the header's "Sign out" button links to. The Express `/logout` endpoint chains oauth2-proxy session clearing with a Keycloak RP-initiated logout. Override to `/oauth2/sign_out?rd=/oauth2/sign_in` if not using Keycloak. | -When deploying with oauth2-proxy, the defaults are correct and no override is needed unless the oauth2-proxy is mounted at a non-standard prefix. +When deploying with oauth2-proxy, set the following two server env vars to enable Keycloak RP-initiated logout: + +| Variable | Example | Description | +|---|---|---| +| `KEYCLOAK_LOGOUT_URL` | `https://auth.app.cogstack.org/realms/cogstack/protocol/openid-connect/logout?client_id=cogstack-cohorter-oauth2-proxy` | Keycloak `end_session_endpoint` with `client_id` appended. When set, clicking "Sign out" first clears the oauth2-proxy session cookie, then redirects the browser to Keycloak to invalidate the SSO session. | +| `POST_LOGOUT_REDIRECT_URI` | `https://cohorter.app.cogstack.org/oauth2/sign_in` | URL Keycloak redirects the browser to after the SSO session is cleared. Should be the oauth2-proxy sign-in page (a public route). Must be registered as a valid post-logout redirect URI in the Keycloak client settings. | + +When neither variable is set (standalone deployment without oauth2-proxy), the `/logout` endpoint simply redirects to `/`. + +> **Keycloak admin setup**: add the `POST_LOGOUT_REDIRECT_URI` value to the **Valid post logout redirect URIs** list in the Keycloak client (`cogstack-cohorter-oauth2-proxy` → Settings → Valid post logout redirect URIs). + +When deploying with oauth2-proxy, the `OAUTH2_*` defaults are correct and no override is needed unless the oauth2-proxy is mounted at a non-standard prefix. In Kubernetes these are set as env vars on the webapp container (via helm `cogstack-cohorter.webapp.env`) and are picked up automatically on the next pod restart. diff --git a/cogstack-cohorter/WebAPP/client-react/src/App.jsx b/cogstack-cohorter/WebAPP/client-react/src/App.jsx index 21f2160..16e869d 100644 --- a/cogstack-cohorter/WebAPP/client-react/src/App.jsx +++ b/cogstack-cohorter/WebAPP/client-react/src/App.jsx @@ -13,7 +13,7 @@ const HEADER_HEIGHT = 80; const runtimeConfig = (typeof window !== 'undefined' && window.__RUNTIME_CONFIG__) || {}; const USERINFO_PATH = runtimeConfig.OAUTH2_USERINFO_PATH || '/oauth2/userinfo'; const LOGIN_PATH = runtimeConfig.OAUTH2_LOGIN_PATH || '/oauth2/sign_in'; -const LOGOUT_PATH = runtimeConfig.OAUTH2_LOGOUT_PATH || '/oauth2/sign_out?rd=/'; +const LOGOUT_PATH = runtimeConfig.OAUTH2_LOGOUT_PATH || '/logout'; function App() { const rootRef = useRef(null); diff --git a/cogstack-cohorter/WebAPP/entrypoint.sh b/cogstack-cohorter/WebAPP/entrypoint.sh index f29b5a4..bbc1d33 100644 --- a/cogstack-cohorter/WebAPP/entrypoint.sh +++ b/cogstack-cohorter/WebAPP/entrypoint.sh @@ -33,7 +33,7 @@ CONFIG_JS=/usr/src/app/client-react/dist/config.js printf 'window.__RUNTIME_CONFIG__ = {\n' printf ' OAUTH2_USERINFO_PATH: "%s",\n' "$(_js_escape "${OAUTH2_USERINFO_PATH:-/oauth2/userinfo}")" printf ' OAUTH2_LOGIN_PATH: "%s",\n' "$(_js_escape "${OAUTH2_LOGIN_PATH:-/oauth2/sign_in}")" - printf ' OAUTH2_LOGOUT_PATH: "%s",\n' "$(_js_escape "${OAUTH2_LOGOUT_PATH:-/oauth2/sign_out?rd=/}")" + printf ' OAUTH2_LOGOUT_PATH: "%s",\n' "$(_js_escape "${OAUTH2_LOGOUT_PATH:-/logout}")" printf '};\n' } > "$CONFIG_JS" diff --git a/cogstack-cohorter/WebAPP/server/server.js b/cogstack-cohorter/WebAPP/server/server.js index 62a2738..9a30908 100644 --- a/cogstack-cohorter/WebAPP/server/server.js +++ b/cogstack-cohorter/WebAPP/server/server.js @@ -677,9 +677,10 @@ app.post('/compare_query', (req, res) => { // configurable default user so the Header/UserSection renders correctly // without any real authentication. app.get("/oauth2/userinfo", (req, res) => { - const groups = process.env.DEFAULT_USER_GROUPS || 'cohorter-users' - ? process.env.DEFAULT_USER_GROUPS.split(',').map(g => g.trim()).filter(Boolean) - : []; + const rawGroups = process.env.DEFAULT_USER_GROUPS; + const groups = rawGroups + ? rawGroups.split(',').map(g => g.trim()).filter(Boolean) + : ['cohorter-users']; res.status(200).json({ user: process.env.DEFAULT_USER_ID || 'local', email: process.env.DEFAULT_USER_EMAIL || '', @@ -689,6 +690,21 @@ app.get("/oauth2/userinfo", (req, res) => { }); //======================================================== +//======================================================== +// Logout — chains oauth2-proxy session clear with Keycloak RP-initiated logout +// when KEYCLOAK_LOGOUT_URL and POST_LOGOUT_REDIRECT_URI env vars are set. +// When KEYCLOAK_LOGOUT_URL is not set (standalone / no oauth2-proxy), redirects to /. +app.get("/logout", (req, res) => { + const keycloakLogoutUrl = process.env.KEYCLOAK_LOGOUT_URL; + if (!keycloakLogoutUrl) { + return res.redirect('/'); + } + const postLogoutUri = process.env.POST_LOGOUT_REDIRECT_URI || '/oauth2/sign_in'; + const keycloakUrl = `${keycloakLogoutUrl}&post_logout_redirect_uri=${encodeURIComponent(postLogoutUri)}`; + res.redirect(`/oauth2/sign_out?rd=${encodeURIComponent(keycloakUrl)}`); +}); +//======================================================== + //======================================================== // api to handle admin_login app.post("/admin_login", (req, res) => {