Files
document-haness/docs/keycloak/tech-log-studio/tech-log-tree.json
T
DongHyeonkaandClaude Opus 5 b2963105a8 docs(keycloak-session-store): import the session-storage lab as a new project
The keycloak project ended with four open questions that design could not
settle. A two-VM lab was built to answer them by measurement, and this is
that material: 26 experiments, 125 raw command outputs, 22 browser captures.

Follows the import procedure in README.md.

  source/     the originating repository verbatim — 78 documents, 28 SVGs,
              8 manifests, plus .source-revision recording the commit
  final/      the SSOT
    document.md   729 lines written from the 29 experiment documents, not
                  concatenated: what was predicted, what was measured, and
                  where the measurement itself was wrong
    evidence/raw    125 outputs, flattened to <experiment>__<file> because
                    the originals collided (01-baseline.txt appeared three
                    times) and the audit only globs the top level
    evidence/meta   one per raw file; command and exitCode are null and the
                    README says why rather than inventing them
    evidence/browser  22 captures
    assets/       three diagrams through techviz
    .techviz/     their VizSpecs

A separate project rather than an addition to keycloak: the B-layer answers
that project's four questions, but the A, C and D layers are about cluster
failure, SSO and operations, and one document.md should hold one subject.
The four question records there can point here through 관계.

Recorded rather than papered over: only three of the 28 diagrams were
remade. The repository forbids hand-drawn SVG and forbids titles inside the
canvas; all 28 originals carry both, so converting them is redrawing, not
reformatting. They stay in source/ and the gap is written into the document.

verify-pipeline.py passes. audit-records.py reports no issues.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-04 22:51:59 +09:00

399 lines
19 KiB
JSON

{
"schemaVersion": 2,
"project": "keycloak",
"ssot": "final/document.md",
"ssotSha256": "0625bc875ab31ca6f331e6f64bd93f26397d54f3ac6e0162f4128a53a1d97e2d",
"generatedAt": "2026-09-04",
"note": "글감 목록이다. file 이 있으면 이미 쓴 기록이고, 없으면 아직 쓰지 않은 글감이다. ssotSha256 이 지금 final/document.md 와 다르면 SSOT 가 바뀐 뒤 트리를 다시 보지 않은 것이다.",
"readinessValues": [
"READY",
"NEEDS_EVIDENCE",
"BLOCKED",
"REJECTED"
],
"topics": {
"oauth-oidc-auth-boundary": {
"topic": "oauth-oidc-auth-boundary",
"kinds": {
"case": [
{
"title": "Refresh Token 관리만 서버로 이전, Access Token은 여전히 Browser에 노출",
"slug": "split-custody-access-token",
"file": "oauth-oidc-auth-boundary/case/case-ap2-split-custody.md",
"readiness": "READY",
"status": "게시 중",
"studioId": "488ce49b-afa4-42a5-a2ce-de2e0653cd82",
"assets": [
"ap2-split-custody-779cb791"
],
"evidence": [],
"relations": [
"SPA에서 토큰을 직접 관리하면서 드러난 Browser Credential 경계",
"Public Client와 Confidential Client 구분 기준",
"OAuth Token과 Application Session을 구분하는 기준",
"OAuth/OIDC 인증 패턴 선택 기준",
"Refresh Token Rotation과 다중 Replica 경쟁을 어떻게 처리할 것인가"
]
},
{
"title": "BFF에서 Browser Token을 제거하고 Session과 CSRF를 처리한 방식",
"slug": "bff-session-csrf-responsibility",
"file": "oauth-oidc-auth-boundary/case/case-ap3-bff-session-csrf.md",
"readiness": "READY",
"status": "게시 중",
"studioId": "d85bd6af-7599-4ef7-9407-6609927d5b5c",
"assets": [
"ap3-bff-custody-82fa18bd",
"ap3-csrf-split-501dd1f7"
],
"evidence": [],
"relations": [
"BFF 인증 구조 설계 기준",
"OAuth Token과 Application Session을 구분하는 기준",
"OAuth/OIDC 인증 패턴 선택 기준",
"BFF가 OAuth Token을 관리하는 조건",
"서버 세션 기반 인증 구조는 다중 인스턴스에서 어떻게 운영할 것인가",
"BFF의 Session과 OAuth2AuthorizedClient를 어디에 저장할 것인가"
]
},
{
"title": "Forward-Auth에서 Client가 보낸 Identity Header를 신뢰하면 안 되는 이유",
"slug": "identity-header-trust",
"file": "oauth-oidc-auth-boundary/case/case-ap4-identity-header-trust.md",
"readiness": "READY",
"status": "게시 중",
"studioId": "a0e1cc05-92b3-4dac-bce1-513ab8cd862b",
"assets": [
"ap4-edge-trust-1cff2399"
],
"evidence": [],
"relations": [
"Forward-Auth에서 Identity Header를 신뢰하기 위한 조건",
"OAuth Token과 Application Session을 구분하는 기준",
"OAuth/OIDC 인증 패턴 선택 기준",
"Forward-Auth 구조에서 Application Authorization을 어디까지 Edge에 둘 것인가"
]
},
{
"title": "SPA에서 OAuth Token을 JavaScript Memory에 보관한 경우",
"slug": "spa-browser-credential-boundary",
"file": "oauth-oidc-auth-boundary/case/case-browser-credential-boundary.md",
"readiness": "READY",
"status": "게시 중",
"studioId": "bf675775-4f3e-4744-8014-f0efff51422a",
"assets": [
"ap1-custody-v3-6e0376d2"
],
"evidence": [],
"relations": [
"Authorization Code Flow의 Endpoint와 Credential 이동 기준",
"Public Client와 Confidential Client 구분 기준",
"OAuth Token과 Application Session을 구분하는 기준"
]
}
],
"concept": [
{
"title": "Authorization Code와 PKCE가 보호하는 구간",
"slug": "authorization-code-and-pkce",
"file": "oauth-oidc-auth-boundary/concept/concept-authorization-code-and-pkce.md",
"readiness": "READY",
"status": "게시 전",
"studioId": "75c6c657-3e03-47a0-a9d0-5637fce9dd3f",
"assets": [],
"evidence": [],
"relations": [
"Authorization Code Flow의 Endpoint와 Credential 이동 기준",
"Public Client와 Confidential Client 구분 기준",
"SPA에서 토큰을 직접 관리하면서 드러난 Browser Credential 경계"
]
},
{
"title": "Bearer JWT가 인증된 principal이 되기까지",
"slug": "bearer-jwt-validation-chain",
"file": "oauth-oidc-auth-boundary/concept/concept-bearer-jwt-validation-chain.md",
"readiness": "READY",
"status": "게시 전",
"studioId": "87000d59-b69f-4010-9481-0b71c8bde32d",
"assets": [],
"evidence": [],
"relations": [
"OAuth Token과 Application Session을 구분하는 기준",
"Authorization Code Flow의 Endpoint와 Credential 이동 기준",
"SPA에서 토큰을 직접 관리하면서 드러난 Browser Credential 경계"
]
},
{
"title": "브라우저가 credential을 보관하는 위치와 그 성질",
"slug": "browser-credential-storage",
"file": "oauth-oidc-auth-boundary/concept/concept-browser-credential-storage.md",
"readiness": "READY",
"status": "게시 전",
"studioId": "bb5c37ae-2d94-48f7-ad4e-a37c61c3fd07",
"assets": [],
"evidence": [],
"relations": [
"OAuth Token과 Application Session을 구분하는 기준",
"SPA에서 토큰을 직접 관리하면서 드러난 Browser Credential 경계",
"BFF 인증 구조 설계 기준"
]
},
{
"title": "Cookie로 인증하는 요청에서 CSRF token이 하는 일",
"slug": "cookie-auth-csrf",
"file": "oauth-oidc-auth-boundary/concept/concept-cookie-auth-csrf.md",
"readiness": "READY",
"status": "게시 전",
"studioId": "5c8f12d5-1ead-469b-8e91-2de69401df48",
"assets": [],
"evidence": [],
"relations": [
"BFF 인증 구조 설계 기준",
"Browser Token을 없애면서 BFF에 Session과 CSRF 책임이 생긴 과정",
"OAuth Token과 Application Session을 구분하는 기준"
]
},
{
"title": "Forward-Auth와 Nginx auth_request의 동작",
"slug": "forward-auth-and-auth-request",
"file": "oauth-oidc-auth-boundary/concept/concept-forward-auth-and-auth-request.md",
"readiness": "READY",
"status": "게시 전",
"studioId": "a3493786-d3fb-4b01-b1c5-ecb23c3d5497",
"assets": [],
"evidence": [],
"relations": [
"Forward-Auth에서 Identity Header를 신뢰하기 위한 조건",
"Forward-Auth에서 Client가 보낸 Identity Header를 신뢰하면 안 되는 이유",
"OAuth/OIDC 인증 패턴 선택 기준"
]
},
{
"title": "외부 IdP Brokering의 동작",
"slug": "idp-brokering",
"file": "oauth-oidc-auth-boundary/concept/concept-idp-brokering.md",
"readiness": "READY",
"status": "게시 전",
"studioId": "d99fdec9-fe9e-4e0f-a50b-6fb9b9ed5719",
"assets": [],
"evidence": [],
"relations": [
"외부 IdP 연동과 Application 인증 구조의 경계",
"OAuth Token과 Application Session을 구분하는 기준",
"Authorization Code Flow의 Endpoint와 Credential 이동 기준"
]
}
],
"reference": [
{
"title": "Authorization Code Flow의 Endpoint와 Credential 이동 기준",
"slug": "authorization-code-endpoint-credential-movement",
"file": "oauth-oidc-auth-boundary/reference/reference-authorization-code-endpoints.md",
"readiness": "READY",
"status": "게시 중",
"studioId": "39fdf472-82c4-43ed-abec-73de672f08ae",
"assets": [],
"evidence": [],
"relations": [
"SPA에서 토큰을 직접 관리하면서 드러난 Browser Credential 경계",
"Refresh Token 관리만 서버로 이전, Access Token은 여전히 Browser에 노출",
"Public Client와 Confidential Client 구분 기준"
]
},
{
"title": "BFF 인증 구조 설계 기준",
"slug": "bff-authentication-design-criteria",
"file": "oauth-oidc-auth-boundary/reference/reference-bff-auth-design.md",
"readiness": "READY",
"status": "게시 중",
"studioId": "97eddd97-1096-426a-a2c6-a6c5bf1cd09f",
"assets": [],
"evidence": [],
"relations": [
"Browser Token을 없애면서 BFF에 Session과 CSRF 책임이 생긴 과정",
"서버 세션 기반 인증 구조는 다중 인스턴스에서 어떻게 운영할 것인가",
"BFF의 Session과 OAuth2AuthorizedClient를 어디에 저장할 것인가",
"BFF가 OAuth Token을 관리하는 조건"
]
},
{
"title": "Forward-Auth에서 Identity Header를 신뢰하기 위한 조건",
"slug": "forward-auth-identity-header-trust",
"file": "oauth-oidc-auth-boundary/reference/reference-forward-auth-header-trust.md",
"readiness": "READY",
"status": "게시 중",
"studioId": "004dd0a2-5fb3-4f25-80c9-576f709de331",
"assets": [],
"evidence": [],
"relations": [
"Forward-Auth에서 Client가 보낸 Identity Header를 신뢰하면 안 되는 이유",
"Forward-Auth 구조에서 Application Authorization을 어디까지 Edge에 둘 것인가",
"OAuth Token과 Application Session을 구분하는 기준"
]
},
{
"title": "외부 IdP 연동과 Application 인증 구조의 경계",
"slug": "external-idp-federation-application-boundary",
"file": "oauth-oidc-auth-boundary/reference/reference-idp-federation-boundary.md",
"readiness": "READY",
"status": "게시 중",
"studioId": "1a00a640-8987-4075-a9e4-7ec023cdffbb",
"assets": [],
"evidence": [],
"relations": [
"외부 IdP와의 연동이라도 별도의 인증 방식이 아니다.",
"SPA에서 토큰을 직접 관리하면서 드러난 Browser Credential 경계",
"Authorization Code Flow의 Endpoint와 Credential 이동 기준"
]
},
{
"title": "OAuth/OIDC 인증 패턴 선택 기준",
"slug": "oauth-oidc-pattern-selection-criteria",
"file": "oauth-oidc-auth-boundary/reference/reference-pattern-selection.md",
"readiness": "READY",
"status": "게시 중",
"studioId": "3f886154-1b85-407b-bda4-57d28370e745",
"assets": [],
"evidence": [],
"relations": [
"SPA에서 토큰을 직접 관리하면서 드러난 Browser Credential 경계",
"Refresh Token 관리만 서버로 이전, Access Token은 여전히 Browser에 노출",
"Browser Token을 없애면서 BFF에 Session과 CSRF 책임이 생긴 과정",
"Forward-Auth에서 Client가 보낸 Identity Header를 신뢰하면 안 되는 이유"
]
},
{
"title": "Public Client와 Confidential Client 구분 기준",
"slug": "public-confidential-client-boundary",
"file": "oauth-oidc-auth-boundary/reference/reference-public-confidential-client.md",
"readiness": "READY",
"status": "게시 중",
"studioId": "ede6b9ce-eeed-40c8-9175-9e8116029395",
"assets": [],
"evidence": [],
"relations": [
"SPA에서 토큰을 직접 관리하면서 드러난 Browser Credential 경계",
"Refresh Token 관리만 서버로 이전, Access Token은 여전히 Browser에 노출",
"Authorization Code Flow의 Endpoint와 Credential 이동 기준"
]
},
{
"title": "OAuth Token과 Application Session을 구분하는 기준",
"slug": "oauth-token-application-session-boundary",
"file": "oauth-oidc-auth-boundary/reference/reference-token-vs-session.md",
"readiness": "READY",
"status": "게시 중",
"studioId": "66c18e42-116c-459f-86bd-b7e4bf394866",
"assets": [],
"evidence": [],
"relations": [
"SPA에서 토큰을 직접 관리하면서 드러난 Browser Credential 경계",
"Refresh Token 관리만 서버로 이전, Access Token은 여전히 Browser에 노출",
"Browser Token을 없애면서 BFF에 Session과 CSRF 책임이 생긴 과정",
"Forward-Auth에서 Client가 보낸 Identity Header를 신뢰하면 안 되는 이유"
]
}
],
"question": [
{
"title": "BFF의 Session과 OAuth2AuthorizedClient를 어디에 저장할 것인가",
"slug": "bff-session-authorized-client-store",
"file": "oauth-oidc-auth-boundary/question/question-bff-state-store.md",
"readiness": "READY",
"status": "게시 중",
"studioId": "18a5cde2-dd1e-4bff-9f1c-997577ae438f",
"assets": [],
"evidence": [],
"relations": [
"서버 세션 기반 인증 구조는 다중 인스턴스에서 어떻게 운영할 것인가",
"Browser Token을 없애면서 BFF에 Session과 CSRF 책임이 생긴 과정",
"BFF 인증 구조 설계 기준",
"Refresh Token Rotation과 다중 Replica 경쟁을 어떻게 처리할 것인가"
]
},
{
"title": "Forward-Auth 구조에서 Application Authorization을 어디까지 Edge에 둘 것인가",
"slug": "edge-authorization-scope",
"file": "oauth-oidc-auth-boundary/question/question-edge-authorization-scope.md",
"readiness": "READY",
"status": "게시 중",
"studioId": "7ff40767-a00b-4db2-98f6-0cdfce8c8936",
"assets": [],
"evidence": [],
"relations": [
"Forward-Auth에서 Client가 보낸 Identity Header를 신뢰하면 안 되는 이유",
"Forward-Auth에서 Identity Header를 신뢰하기 위한 조건",
"BFF 인증 구조 설계 기준"
]
},
{
"title": "서버 세션 기반 인증 구조는 다중 인스턴스에서 어떻게 운영할 것인가",
"slug": "server-session-pattern-multi-instance",
"file": "oauth-oidc-auth-boundary/question/question-multi-instance-session.md",
"readiness": "READY",
"status": "게시 중",
"studioId": "c72656b5-842d-45d9-b5f6-82b66b09d0b9",
"assets": [],
"evidence": [],
"relations": [
"Browser Token을 없애면서 BFF에 Session과 CSRF 책임이 생긴 과정",
"Refresh Token 관리만 서버로 이전, Access Token은 여전히 Browser에 노출",
"BFF 인증 구조 설계 기준",
"BFF의 Session과 OAuth2AuthorizedClient를 어디에 저장할 것인가"
]
},
{
"title": "Refresh Token Rotation과 다중 Replica 경쟁을 어떻게 처리할 것인가",
"slug": "refresh-rotation-replica-contention",
"file": "oauth-oidc-auth-boundary/question/question-refresh-rotation-replica.md",
"readiness": "READY",
"status": "게시 중",
"studioId": "9ae4ec71-a32e-49a7-88c2-f7368541c28d",
"assets": [],
"evidence": [],
"relations": [
"BFF의 Session과 OAuth2AuthorizedClient를 어디에 저장할 것인가",
"Refresh Token 관리만 서버로 이전, Access Token은 여전히 Browser에 노출",
"서버 세션 기반 인증 구조는 다중 인스턴스에서 어떻게 운영할 것인가",
"BFF 인증 구조 설계 기준"
]
}
],
"decision": [
{
"title": "BFF가 OAuth Token을 관리하는 조건",
"slug": "bff-owns-token-when-browser-must-not",
"file": "oauth-oidc-auth-boundary/decision/decision-bff-owns-token.md",
"readiness": "READY",
"status": "게시 중",
"studioId": "19b55c39-c583-4161-9775-df954280a568",
"assets": [],
"evidence": [],
"relations": [
"Browser Token을 없애면서 BFF에 Session과 CSRF 책임이 생긴 과정",
"BFF 인증 구조 설계 기준",
"OAuth/OIDC 인증 패턴 선택 기준",
"Refresh Token 관리만 서버로 이전, Access Token은 여전히 Browser에 노출"
]
},
{
"title": "외부 IdP와의 연동이라도 별도의 인증 방식이 아니다.",
"slug": "federation-is-not-an-application-pattern",
"file": "oauth-oidc-auth-boundary/decision/decision-federation-not-a-pattern.md",
"readiness": "READY",
"status": "게시 중",
"studioId": "8c1ebea7-204e-445c-9812-0421d9eb0e9c",
"assets": [],
"evidence": [],
"relations": [
"외부 IdP 연동과 Application 인증 구조의 경계",
"SPA에서 토큰을 직접 관리하면서 드러난 Browser Credential 경계",
"OAuth Token과 Application Session을 구분하는 기준"
]
}
]
}
}
}
}