{ "version": "1.1", "id": "c2-backchannel-both-sides", "title": "백채널 로그아웃은 양쪽이 있어야 한다", "question": "IdP 쪽만 설정하면 로그아웃이 퍼지는가", "type": "architecture", "direction": "TB", "audience": [ "SSO 로그아웃을 구현하려는 백엔드 엔지니어" ], "summary": "IdP 의 backchannelLogoutUrl 과 앱의 수신 엔드포인트가 둘 다 있어야 한다. 이 실험대에는 둘 다 없었다.", "alt": "Keycloak 이 부를 주소와 앱이 받을 엔드포인트가 각각 비어 있어 로그아웃 통지가 어느 쪽에서도 성립하지 않는 구성.", "long_description": "C-1 에서 로그아웃이 다른 앱으로 퍼지지 않는 것을 관측했고 원인은 단순했다. 두 클라이언트 모두 backchannelLogoutUrl 이 비어 있어 Keycloak 은 부를 주소를 몰랐고, BFF 소스에는 oidcLogout 설정이 없어 주소를 알려줘도 받을 곳이 없었다. Keycloak 파드에서 앱 URL 로 요청하면 200 이 돌아오므로 네트워크 문제도 아니다. 설정이 빠졌다와 기능이 없다는 다르게 고쳐야 하는데 여기는 둘 다였다.", "source_context": { "document": "docs/keycloak-session-store/final/document.md", "document_sha256": "1d44cba1905544d92f1d26ae36a8deb64a3db3914d6b488fd30d6ae7f8cfbabe", "anchor": { "kind": "heading", "value": "C층 — SSO 와 로그아웃 전파", "line": 464 } }, "composition": { "profile": "component-flow", "diagram_only": true, "reference_ids": [ "payment-event-flow" ], "rationale": "통지가 끊기는 지점이 한 곳이 아니라는 것이 지배적 질문이다. 경로의 두 결손이므로 component-flow 를 골랐다." }, "groups": [], "nodes": [ { "id": "logout", "label": "한 앱에서 로그아웃", "kind": "actor", "role": "source", "emphasis": "primary", "description": "Keycloak 세션이 끝난다.", "details": [], "evidence": [ { "start_line": 458, "end_line": 465 } ], "assumption": false }, { "id": "kc-config", "label": "backchannelLogoutUrl", "kind": "component", "role": "control", "emphasis": "warning", "description": "클라이언트 설정. 비어 있었다.", "details": [ "주소 없음" ], "evidence": [ { "start_line": 458, "end_line": 466 } ], "assumption": false }, { "id": "app-endpoint", "label": "앱의 수신 엔드포인트", "kind": "component", "role": "control", "emphasis": "warning", "description": "소스에 없었다.", "details": [ "oidcLogout 설정 없음" ], "evidence": [ { "start_line": 458, "end_line": 466 } ], "assumption": false }, { "id": "app-session", "label": "다른 앱의 세션", "kind": "component", "role": "target", "emphasis": "warning", "description": "그대로 남는다.", "details": [ "네트워크 도달 200" ], "evidence": [ { "start_line": 458, "end_line": 466 } ], "assumption": false } ], "edges": [ { "id": "l-c", "from": "logout", "to": "kc-config", "label": "통지 주소 조회", "kind": "request", "evidence": [ { "start_line": 458, "end_line": 466 } ], "assumption": false }, { "id": "c-e", "from": "kc-config", "to": "app-endpoint", "label": "호출 (주소 필요)", "kind": "blocked", "evidence": [ { "start_line": 458, "end_line": 466 } ], "assumption": false }, { "id": "e-s", "from": "app-endpoint", "to": "app-session", "label": "세션 삭제 (엔드포인트 필요)", "kind": "blocked", "evidence": [ { "start_line": 458, "end_line": 466 } ], "assumption": false } ], "legend": [], "metadata": { "rationale": "IdP 쪽 결손과 앱 쪽 결손을 한 경로 위에 나란히 놓았다. 하나만 고치면 여전히 안 된다." } }