diff --git a/.env.example b/.env.example index a4be742..9a1b3c2 100644 --- a/.env.example +++ b/.env.example @@ -1,7 +1,6 @@ KEYCLOAK_CLIENT_ID="tjwater" KEYCLOAK_CLIENT_SECRET="replace-with-keycloak-client-secret" KEYCLOAK_ISSUER="https://keycloak.example.com/realms/tjwater" -KEYCLOAK_POST_LOGOUT_REDIRECT_URI="http://localhost:3000/login" NEXTAUTH_SECRET="replace-with-nextauth-secret" NEXTAUTH_URL="https://frontend.example.com/" diff --git a/docker-compose.yml b/docker-compose.yml index adae578..77938c1 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -18,7 +18,6 @@ services: KEYCLOAK_CLIENT_ID: ${KEYCLOAK_CLIENT_ID} KEYCLOAK_CLIENT_SECRET: ${KEYCLOAK_CLIENT_SECRET} KEYCLOAK_ISSUER: ${KEYCLOAK_ISSUER} - KEYCLOAK_POST_LOGOUT_REDIRECT_URI: ${KEYCLOAK_POST_LOGOUT_REDIRECT_URI} NEXTAUTH_SECRET: ${NEXTAUTH_SECRET} NEXTAUTH_URL: ${NEXTAUTH_URL} NODE_ENV: production diff --git a/src/app/api/auth/keycloak-logout/route.test.ts b/src/app/api/auth/keycloak-logout/route.test.ts index b082d6b..d63c0bb 100644 --- a/src/app/api/auth/keycloak-logout/route.test.ts +++ b/src/app/api/auth/keycloak-logout/route.test.ts @@ -48,7 +48,7 @@ describe("GET /api/auth/keycloak-logout", () => { { headers: { cookie: - "__Secure-next-auth.session-token.0=first; __Secure-next-auth.session-token.1=second", + "__Secure-next-auth.session-token.0=first; __Secure-next-auth.session-token.1=second; next-auth.session-token=local", }, }, ); @@ -65,11 +65,22 @@ describe("GET /api/auth/keycloak-logout", () => { ); expect(logoutUrl.searchParams.get("client_id")).toBe("tjwater"); expect(logoutUrl.searchParams.get("post_logout_redirect_uri")).toBeNull(); - expect(response.cookies.get("__Secure-next-auth.session-token.0")?.value).toBe(""); - expect(response.cookies.get("__Secure-next-auth.session-token.1")?.value).toBe(""); + expect( + response.cookies.get("__Secure-next-auth.session-token.0"), + ).toMatchObject({ value: "", path: "/", secure: true }); + expect( + response.cookies.get("__Secure-next-auth.session-token.1"), + ).toMatchObject({ value: "", path: "/", secure: true }); + expect(response.cookies.get("next-auth.session-token")).toMatchObject({ + value: "", + path: "/", + }); + expect( + response.cookies.get("next-auth.session-token")?.secure, + ).toBeFalsy(); }); - it("uses an explicitly configured post-logout redirect URI", async () => { + it("ignores a legacy automatic post-logout redirect setting", async () => { process.env.KEYCLOAK_POST_LOGOUT_REDIRECT_URI = "https://frontend.example.com/login"; getTokenMock.mockResolvedValue({ idToken: "header.payload.signature" }); @@ -81,8 +92,6 @@ describe("GET /api/auth/keycloak-logout", () => { ); const logoutUrl = new URL(response.headers.get("location") ?? ""); - expect(logoutUrl.searchParams.get("post_logout_redirect_uri")).toBe( - "https://frontend.example.com/login", - ); + expect(logoutUrl.searchParams.get("post_logout_redirect_uri")).toBeNull(); }); }); diff --git a/src/app/api/auth/keycloak-logout/route.ts b/src/app/api/auth/keycloak-logout/route.ts index f7d369a..6cfaf89 100644 --- a/src/app/api/auth/keycloak-logout/route.ts +++ b/src/app/api/auth/keycloak-logout/route.ts @@ -20,8 +20,6 @@ export const GET = async (request: NextRequest) => { ); const issuer = process.env.KEYCLOAK_ISSUER?.replace(/\/$/, ""); const clientId = process.env.KEYCLOAK_CLIENT_ID; - const postLogoutRedirectUri = - process.env.KEYCLOAK_POST_LOGOUT_REDIRECT_URI; const token = (await getToken({ req: request, secret: process.env.NEXTAUTH_SECRET, @@ -33,17 +31,17 @@ export const GET = async (request: NextRequest) => { if (issuer) { if (clientId) logoutUrl.searchParams.set("client_id", clientId); if (token?.idToken) logoutUrl.searchParams.set("id_token_hint", token.idToken); - if (postLogoutRedirectUri) { - logoutUrl.searchParams.set( - "post_logout_redirect_uri", - postLogoutRedirectUri, - ); - } } const response = NextResponse.redirect(logoutUrl); for (const { name } of request.cookies.getAll()) { - if (isSessionCookie(name)) response.cookies.delete(name); + if (isSessionCookie(name)) { + response.cookies.delete({ + name, + path: "/", + secure: name.startsWith("__Secure-"), + }); + } } return response;