13 KiB
13 KiB
title, source_type, status, id, kind, project, work_item, inherits, refines, overrides, depends_on, imports, delegates, accepts_delegations, contract_packet, contract_packet_sha256, branch, parent_branch, related_projects, tags, created, target_merge, status_label
| title | source_type | status | id | kind | project | work_item | inherits | refines | overrides | depends_on | imports | delegates | accepts_delegations | contract_packet | contract_packet_sha256 | branch | parent_branch | related_projects | tags | created | target_merge | status_label | |||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| branch / feature-keycloak-token-mediating-access-handoff | branch-note | raw | BR-KEYCLOAK-PATTERNS-OVERVIEW-009 | project-work-item | keycloak-patterns-overview | WI-KEYCLOAK-PATTERNS-OVERVIEW-009 |
|
|
1 | 76cd5b845d8e9bd8eb75e0a2f2c46adad06c6b67eb9bf358ada252205ad86f82 | feature-keycloak-token-mediating-access-handoff |
|
|
2026-07-24 | in-progress |
branch: feature-keycloak-token-mediating-access-handoff
부모 (필수)
브랜치 계약 패킷
- 생성 시 프로젝트 개정:
1 - 패킷 스키마:
contract_packet: 1 - 완료 조건: browser가 access token으로 API 200을 받고 refresh token은 network response에 존재하지 않는다
상속한 프로젝트 결정
| Decision Ref | Project Summary | Branch Application | Source |
|---|---|---|---|
DEC-KEYCLOAK-PATTERNS-OVERVIEW-ACCEPTANCE-001@1 |
done-bar는 E2E success와 signature security failure 재현·해결 evidence다 | WI-KEYCLOAK-PATTERNS-OVERVIEW-009 완료 조건에 적용 |
[[raw/project-notes/keycloak-patterns-overview]] |
DEC-KEYCLOAK-PATTERNS-OVERVIEW-TOKEN-MEDIATING-001@1 |
AP2 backend가 token을 획득하고 access token만 browser에 전달한다 | WI-KEYCLOAK-PATTERNS-OVERVIEW-009 완료 조건에 적용 |
[[raw/project-notes/keycloak-patterns-overview]] |
브랜치 지역 결정
| Decision ID | Decision | Relation | Supporting Claims | Status |
|---|
선언한 예외
| Override ID | Overrides | Reason | Approval | Status |
|---|
가져온 artifact 계약
| Artifact Ref | Owner | Producer | Schema Ref |
|---|
가져온 프로젝트 계약
| Ref | Owner | 요약 | Branch 적용 |
|---|
수신한 위임
| Delegation Ref | From | Concern | Status |
|---|
가져온 흐름 단계
| Stage Ref | Order | Owner | Input | Action | Output |
|---|
목표
WI-KEYCLOAK-PATTERNS-OVERVIEW-009의 완료 조건을 구현한다: browser가 access token으로 API 200을 받고 refresh token은 network response에 존재하지 않는다
범위
포함 범위
- backend 가 획득한 토큰 중 access token 만 browser 로 handoff → browser 가 Resource Server 를 직접 호출(proxy 없음)
200. - refresh token 이 browser 로 가는 network response(응답 바디/헤더/쿠키)에 부재함을 확인(refresh 는 backend 만 보유).
- 위 두 가지를 로컬 스택에서 네트워크 탭/응답 검사로 재현·검증.
제외 범위
의도적으로 제외. 면접 등에서 "이건 범위에 없었습니다" 근거.
- backend 의 code→token 교환 + refresh 서버측 보관 자체 →
WI-008(feature-keycloak-token-mediating-confidential-client) 소유. 본 branch 는 그 산출물(서버측 보관 access)을 browser 로 넘기는 경계만. - BFF(모든 요청 proxy) → AP3. 본 패턴은 proxy 없이 access 를 browser 에 위임(TMB 의 정의적 차이).
- project decision registry 변경.
근거 (필수, 최소 1개+)
| Source | 정당화하는 결정 |
|---|---|
[[raw/official-docs/oauth2-browser-based-apps-ietf-draft]] |
D1·D2 — Token-Mediating Backend 정의: backend 가 confidential client 로 토큰 획득 후 access token 을 앱에 건네 RS 와 직접 통신(OAUTH-BBA-C2), BFF 대비 proxy 불필요·보안수준 낮음(OAUTH-BBA-C5), BFF 는 어떤 토큰도 browser 미노출(OAUTH-BBA-C1, 대비 근거) |
[[raw/company-tech-blogs/curity-bff-pattern-spa]] |
D2 — token 을 browser 에 두는 것의 위험(대비 사례, company-case-study — 단독 official 단언 불가) |
[[raw/branch-notes/feature-keycloak-token-mediating-confidential-client]] |
의존 — WI-008 이 서버측에 보관한 access/refresh 를 consume |
TODO
- backend 가 access token 만 browser 로 전달하는 handoff 경로 구현 — 등급:
planned - browser 가 그 access token 으로
/api200(RS 직접 호출) — 등급:planned - refresh token 이 browser network response 에 부재함을 네트워크 탭/응답 바디로 확인 — 등급:
planned
진행 중 메모
- 본 branch 는 WI-008(획득·서버보관)에 의존하며, "browser 로 무엇을 넘기는가"의 경계만 결정. AP2 구현 코드 미존재(
NO_GROUND_TRUTH) → 전부planned.
결정 사항
- 2026-07-24: D1 access token 만 browser 로 handoff, browser 가 RS 를 직접 호출(proxy 없음) / 이유: TMB 정의(backend 가 획득하되 access 를 앱에 위임) — BFF 대비 경량 / 대안: BFF(AP3, 모든 API proxy·browser 토큰 0개) 또는 browser-client(AP1, browser 가 OAuth 전담) / 근거:
[[raw/official-docs/oauth2-browser-based-apps-ietf-draft]] - 2026-07-24: D2 refresh token 은 browser 로 가는 response 에 포함하지 않음(backend 만 보유) / 이유: refresh 노출 시 XSS 1건=장기 세션 탈취, TMB 는 browser-client 보다 안전한 지점이 바로 이것 / 대안: browser 에 refresh 도 전달(browser-client 로 강등) / 근거:
[[raw/official-docs/oauth2-browser-based-apps-ietf-draft]](OAUTH-BBA-C1·C2대비) - 2026-07-24: D3(상속
DEC-…-ACCEPTANCE-001@1) 완료 판정 = browser/api200AND refresh 가 network 에 부재 / 본 branch 적용점: 두 조건 동시 충족만 done
Decision Evidence Map / 결정-근거 매핑
official-standard(IETF draft) 우선,company-case-study(Curity)는 보조(단독 official 단언 금지). IETF 는 일반 패턴 정의 → project 매핑은 Open Risk.
| Decision ID | Decision | 선택 조건 (언제 이 결정 / 언제 대안) | Supporting Claims | Evidence Strength | Open Risk |
|---|---|---|---|---|---|
| D1 | access token 만 browser 로 handoff, browser 가 RS 직접 호출(proxy 없음) | TMB(AP2) → 이 결정 / BFF(AP3, 전 요청 proxy) 또는 browser-client(AP1) → 대안 | raw/official-docs/oauth2-browser-based-apps-ietf-draft.md#OAUTH-BBA-C2, #OAUTH-BBA-C5 |
official-standard |
draft 는 "access 를 앱에 제공"만 서술 — handoff 메커니즘(응답 바디 JSON / readable cookie / 전용 엔드포인트)은 규정 안 함 → 구현 결정 |
| D2 | refresh token 을 browser response 에 미포함(backend 만 보유) | TMB(refresh 서버측) → 이 결정 / browser-client(refresh 브라우저) → 대안 | raw/official-docs/oauth2-browser-based-apps-ietf-draft.md#OAUTH-BBA-C1, #OAUTH-BBA-C2, raw/company-tech-blogs/curity-bff-pattern-spa.md#CURITY-BFF-C6, [[raw/branch-notes/feature-keycloak-token-mediating-confidential-client]] D2 |
official-standard + company-case-study(보조) |
draft 는 refresh 부재를 직접 문장화하지 않고 "access 만 제공"에서 함의 — refresh 부재 보장 방법(응답에서 제외)은 구현 결정. refresh 노출의 why(탈취 시 유효기간 내내 데이터 접근)는 CURITY-BFF-C6 이 pin(company-case-study 보조 — 단독 official 단언 불가) |
| D3 | 완료 판정 = browser /api 200 AND refresh network 부재 (상속 acceptance) |
항상 / N/A | raw/project-notes/keycloak-patterns-overview.md (DEC-KEYCLOAK-PATTERNS-OVERVIEW-ACCEPTANCE-001@1, 상속) |
project-decision(inherited) |
"network 부재"의 검사 범위(응답 바디만 vs 헤더·쿠키 포함)를 명시적으로 정의해야 함 |
구현 가이드
Trace: D1(
OAUTH-BBA-C2/C5) + D2(OAUTH-BBA-C1/C2+ WI-008 D2) + D3(inherited acceptance). AP2 코드 부재(NO_GROUND_TRUTH)라 사전 명세이며 등급planned.
- UNSUPPORTED_IMPL_DECISION: (a) handoff 메커니즘 — backend 가 access 를 browser 에 전달하는 방식(로그인 후 backend 엔드포인트가 access 를 JSON 으로 반환 / JS-readable 쿠키 / postMessage 등). IETF draft 는 "제공한다"만 서술, 방식 미규정. trade-off: JSON 반환은 단순하나 access 를 JS 가 읽어 XSS 노출면 존재(TMB 의 알려진 한계), readable cookie 도 유사. 근거 없음 → 착수 시 결정. (b) refresh 부재 검사 범위 — 응답 바디만 vs 헤더/Set-Cookie 전수. trade-off: 바디-only 는 간단하나 Set-Cookie 경유 누출을 놓침 / 전수는 안전(누출 지점 전부 커버)하나 검사 비용↑. 본 branch 는 전수 검사로 수렴(아래 refresh 격리 row · §Claims To Verify 와 정합) — 잔여 미결 아님.
| 항목 | 사전 명세 (planned) | Trace |
|---|---|---|
| Handoff endpoint | 로그인 완료 후 backend 가 access token(만)을 browser 에 반환하는 경로 | D1 · UNSUPPORTED_IMPL_DECISION(a) |
| Browser→RS | browser 가 받은 access 로 Authorization: Bearer 붙여 RS /api 직접 호출 200 |
D1(OAUTH-BBA-C2) |
| refresh 격리 | handoff 응답(바디·헤더·쿠키)에서 refresh 제외 — refresh 는 WI-008 서버측 보관에만 존재 | D2 · UNSUPPORTED_IMPL_DECISION(b) |
엣지·실패·의존
- 실패·엣지 경로:
- browser 의 access token 만료 → browser 가 backend handoff 엔드포인트에서 재수령(backend 가 WI-008 D2 로 자동 refresh 후 새 access 발급). refresh 자체 만료 시 재로그인.
- handoff 응답에 refresh 가 실수로 포함 → 완료조건 위반(D3). 검증 대상.
- 다른 계약 의존:
WI-KEYCLOAK-PATTERNS-OVERVIEW-008(feature-keycloak-token-mediating-confidential-client) D1·D2 — 서버측 토큰 획득·보관을 consume. 그 계약이 바뀌면(저장소·refresh 정책) 본 branch handoff 영향. 특히 handoff 엔드포인트가 browser 를 인증하는 방식(세션 쿠키 vs 기타)은 WI-008 의 세션모델(oauth2Login()세션 vs 수동 grant — WI-008 §구현 가이드UNSUPPORTED_IMPL_DECISION(a))에 커플링. WI-008 이 그 축을 정하면 본 branch handoff 인증도 결정된다.WI-KEYCLOAK-PATTERNS-OVERVIEW-004(feature-keycloak-spring-rs-audience-validator) D1·D6 — browser→RS200이 소비하는 Resource Server 의 baseline JWT 검증(issuer-uri/JWKS discovery = D6, signature·iss·exp·aud= D1)을 consume. AP2 가 이 AP1 RS 를 재사용하는지 AP2 backend 가 RS 를 겸직하는지는 착수 시 결정(planned). AP2 done-bar(D3)의 signature 함정은 refresh-부재 축이라aud검증은 본 branch 완료조건에 비필수(RS 소유 브랜치의 관심사).
검증해야 할 주장 / Claims To Verify
IETF draft 는 패턴 정의(메커니즘 근거)지만 본 프로젝트 실제 동작을 자동 보장하지 않는다. AP2 코드 미구현이라 전부 구현 후 검증.
| Claim | Why uncertain | How to verify | Status |
|---|---|---|---|
| browser 가 backend 로부터 access token(만) 수령 | handoff 메커니즘 미결(UNSUPPORTED_IMPL_DECISION a) | 로그인 후 handoff 응답에 access 존재 + refresh 부재 확인 | planned |
browser 가 그 access 로 RS /api 200(직접 호출) |
AP2 코드 미구현 | 네트워크 탭에서 browser→RS 직접 요청 + 200 확인 |
planned |
| refresh token 이 browser 로 가는 network response 에 부재 | 부재 보장 방법(응답 제외) 미구현 · 검사 범위 미정(b) | 네트워크 탭 응답 바디·헤더·Set-Cookie 전수 검사에서 refresh 부재 확인 | planned |
관심사 커버리지 (coverage-auditor 자동 생성 — 있을 때)
/coverage 실행 전.
마주친 문제
아직 없음.
묶음 (이 branch에서 파생된 자료)
관련 일일 노트
해당 없음.
완료 후 정리
- PR 링크:
- 리뷰 메모: