76 KiB
title, source_type, status, confidence, tags, related_projects, last_reviewed, diagrams, architecture_review, status_label, project_revision, url, semantic_surface_exclusions
| title | source_type | status | confidence | tags | related_projects | last_reviewed | diagrams | architecture_review | status_label | project_revision | url | semantic_surface_exclusions | |||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| keycloak-patterns Overview (canonical SSOT) | project-note | raw | medium |
|
|
2026-07-14 |
|
2026-05-26 | active | 1 |
|
keycloak-patterns Overview
본 문서는 keycloak-patterns 프로젝트의 canonical SSOT (Single Source of Truth)입니다. 모든 branch-note는 본 문서를 기준으로 작업하며, 본 문서가 정의하지 않은 결정은 sub-branch 내부에서 자체 결정.
위계 (CLAUDE.md §2/§15):
- 본 문서: 프로젝트 전반 정의 (canonical SSOT)
raw/branch-notes/feature-keycloak-patterns.md: 작업 root (전체 진행 인덱스)raw/branch-notes/feature-keycloak-<pattern-name>.md: 6 패턴별 sub-branch (예:feature-keycloak-edge-forwardauth-no-google)raw/branch-notes/feature-keycloak-<implementation-topic>.md: 패턴별 세부 단계 sub-sub-branch (예:feature-keycloak-oauth2-proxy-oidc-flow)- 계층 정보는 frontmatter
parent_branch:+ 각 파일의## Parent섹션에서 추적- 구현 코드:
/home/donghyeon/workspace/keycloak-patterns/(별도 git repo, LLM Wiki 외부)
1. 프로젝트 정의
한 줄 설명
vanilla JS 클라이언트 + Keycloak Authorization Server + Spring Boot 연동의 4가지 인증 통합 아키텍처 패턴(AP1~AP4) 을 비교·이해·구현하는 학습 + 구현 프로젝트. (분류축 교정 2026-07-14 — 기존 "6가지 배치×federation" 은 §2 로 재편; 배포 토폴로지·Google federation 은 각 패턴에 얹는 cross-cutting 변형.)
본인 역할
- 개인 프로젝트
- 본인이 맡은 영역: 전 영역 (인프라 + 백엔드 + 프론트 + Keycloak 운영 학습)
- 기간: 2026-05-25 ~ 미정
목표 (WHY)
면접에서 "왜 이 배치를 택했나" / "Google 로그인이 붙으면 흐름이 어떻게 바뀌나" / "BFF vs SPA Direct OIDC trade-off는?"에 자신 있게 답할 수 있는 수준의 이해 + 4 인증-아키텍처 패턴 실 구현.
분류축 교정 (2026-07-14): 기존 목표는 "배치×federation 6패턴 이해 + P3A 한정 실 구현" 이었으나, 그 6축은 배포 토폴로지 × Google 이라 keycloak 인증 아키텍처를 2종만 exercise 하고 AP2·AP3 는 누락돼 있었다. §2 에서 primary 축을 인증 통합 아키텍처 4패턴 으로 교정하고, 이 4패턴 실 구현을 새 목표로 삼는다. 상세 근거·매핑은 §2.
성공 기준 (측정가능, R1)
"잘 이해했다" 류 정성 표현 금지. 각 패턴이 "끝났다"고 말할 검증 가능한 결과로 정의한다. done-bar = E2E 검증 + 그 패턴의 signature 함정 의도 재현 → 해결 (2026-07-14 사용자 확정).
패턴 공통 done (4 패턴 각각 + Google cross-cutting 1회):
- E2E: 브라우저 로그인 → 토큰 발급 → 보호 API
200 OK를 로컬(docker compose up)에서 관찰 — curl 로그 또는 스크린샷 증거 첨부. 등급locally-verified. - Signature 함정 재현 → 해결: 그 패턴의 대표 실패를 의도적으로 재현(4xx / 토큰 누출)한 뒤 고치고, before/after 를 기록.
| 패턴 | E2E 성공 신호 | 재현 → 해결할 signature 함정 |
|---|---|---|
| AP1 SPA-direct + Resource Server | SPA 가 받은 access_token 으로 /api 200 |
(a) aud 미검증 → 타 client 토큰 통과 재현 → audience validator 로 401 (b) KC_HOSTNAME 미설정 → iss mismatch 401 재현 → 설정으로 해결 |
| AP2 Token-Mediating Backend | 백엔드(confidential client)가 발급받은 access_token 을 브라우저에 전달, 브라우저가 RS 직접 호출 200 | refresh token 이 브라우저에 노출 안 됨(백엔드만 보유) 을 네트워크 탭 / 응답 바디로 확인 |
| AP3 BFF | 브라우저에 토큰 0개(session cookie 만) 확인, BFF proxy 경유 API 200 | CSRF surface(cookie 자동첨부) 재현 → SameSite / CSRF token 으로 차단 |
| AP4 Edge forward-auth | 미인증 요청 → Keycloak redirect, 인증 후 backend 가 X-Forwarded-User 수신 200 |
X-Forwarded-User 위조로 우회 재현 → NetworkPolicy / SG 로 차단 |
| (cross) Google brokering | Google 계정 로그인 → Keycloak 사용자 매핑 → 위 패턴 흐름 재개 200 | email_verified=false auto-linking 계정탈취 재현 → Confirm Link Existing Account 로 차단 |
프로젝트 완료 신호: 위 표의 4 패턴 + Google cross-cutting 이 모두 locally-verified + 트레이드오프 매트릭스 branch 가 4패턴의 {토큰 위치 · 검증 주체 · XSS/CSRF surface · 선택 기준 · keycloak 설정} 을 한 표로 답할 수 있음.
2. 인증 아키텍처 분류 (canonical 분류 축 — 2026-07-14 교정)
분류축 교정 (2026-07-14). 기존 분류축은 배치 위치 3 × Google federation 2 = 6 패턴 이었으나, 이는 배포 토폴로지 × federation 축이라 keycloak 인증 아키텍처 는 2종(edge-forward-auth, SPA-direct)만 exercise 하고 나머지는 변형이었다(P2≡P3 는 auth 동일, B=A+realm 설정). 멘토가 말한 "4 패턴" 은 인증 통합 아키텍처(누가 토큰을 쥐고, 누가 인증을 강제하나) 축이며, 이것이 keycloak client 통합의 canonical 축이다. 아래로 primary 축을 교체하고, 기존 6 축은 §2.2 cross-cutting 변형으로 강등한다.
근거: raw/official-docs/oauth2-browser-based-apps-ietf-draft (IETF — 브라우저앱 아키텍처 3종 BFF / Token-Mediating Backend / Browser-based OAuth Client 을 보안강도 내림차순 으로 정의), raw/company-tech-blogs/curity-bff-pattern-spa.
2.1 Primary 축 — 인증 통합 아키텍처 4 패턴
축: 누가 access/refresh token 을 보관하고, 누가 인증을 강제하는가. IETF draft-ietf-oauth-browser-based-apps 의 3 패턴 + 별도 인프라 프록시 강제(oauth2-proxy) = 4.
| ID | 패턴 | 토큰 위치 | 인증 강제 주체 | 백엔드 keycloak 역할 | 보안강도 (IETF) |
|---|---|---|---|---|---|
| AP1 | Browser-based OAuth Client (SPA-direct + Resource Server) | 브라우저(JS) | SPA 자신 (public client + PKCE) | Resource Server — JWKS 로 JWT 검증 | 낮음 (토큰 브라우저 노출) |
| AP2 | Token-Mediating Backend | access → 브라우저, refresh → 백엔드 | 백엔드 (confidential client) 가 토큰 획득 후 access token 만 전달 | confidential client + RS | 중 |
| AP3 | Backend-for-Frontend (BFF) | 백엔드 (session) | 백엔드 (confidential client), 모든 API proxy | confidential client + session holder | 높음 (토큰 브라우저 미노출) |
| AP4 | Edge / Gateway forward-auth | 프록시 (session) | 별도 reverse proxy (oauth2-proxy / Traefik) | 프록시가 OIDC, 백엔드는 헤더 신뢰 (인증코드 0줄) | 프록시 network 격리에 의존 |
IETF 보안강도 내림차순 = BFF(AP3) > Token-Mediating(AP2) > Browser-client(AP1). AP4 는 IETF 3종 밖(별도 인프라 프록시)이나 실무의 4번째 패턴.
2.2 Cross-cutting 변형 (별도 패턴 아님 — 각 AP 에 얹음)
- 배포 토폴로지: single-EC2(학습·실 구현) / cluster-internal / edge. 인증 아키텍처를 바꾸지 않고 hostname·issuer·network 경계만 바꿈. signature 함정:
KC_HOSTNAMEiss mismatch, reverse-proxy 헤더. - Google IdP brokering (federation): realm 에 Google 을 외부 IdP 로 등록. 노트 실측대로 SPA/Backend 코드 0줄 변경 — 어느 AP 에도 동일하게 얹힘. signature 함정: First Broker Login email auto-linking.
2.3 기존 6 패턴 → 신 4 패턴 매핑 (기존 작업 재배치, 폐기 아님)
기존 34 branch-note 는 폐기하지 않고 아래로 re-map. 실제 rename/re-parent 은
wiki-doc-author mode=migrate로 점진 수행(자동 mv 금지 — wikilink 영향 검토).
| 기존 (배치×federation) | 신 primary (auth 축) | 신 cross-cutting | 기존 sub-branch |
|---|---|---|---|
| P1A Edge no-google | AP4 Edge forward-auth | 배포=edge | raw/branch-notes/feature-keycloak-edge-forwardauth-no-google |
| P1B Edge + Google | AP4 | +Google brokering | raw/branch-notes/feature-keycloak-edge-forwardauth-google-federation |
| P2A Internal SPA-direct no-google | AP1 SPA-direct + RS | 배포=internal | raw/branch-notes/feature-keycloak-internal-spa-direct-no-google |
| P2B Internal + Google | AP1 | 배포=internal, +Google | raw/branch-notes/feature-keycloak-internal-spa-direct-google-federation |
| P3A Single-EC2 no-google | AP1 SPA-direct + RS | 배포=single-EC2 (실 구현 base) | raw/branch-notes/feature-keycloak-single-ec2-no-google |
| P3B Single-EC2 + Google | AP1 | 배포=single-EC2, +Google | raw/branch-notes/feature-keycloak-single-ec2-google-federation |
| (없음) | AP2 Token-Mediating Backend | — | 신규 — 기존 6 에 없던 패턴 |
| (bff-vs-spa-direct, out-of-scope 비교문서) | AP3 BFF | — | raw/branch-notes/feature-keycloak-bff-vs-spa-direct → AP3 비교 근거(FOLD-IN); 실 구현은 신규 feature-keycloak-bff-oauth2login-session·-bff-csrf-samesite-defense |
핵심: 기존 "6 구현" 은 실제로 auth 아키텍처 2종(AP1, AP4)의 배포·federation 변형이었고 AP2·AP3 는 누락돼 있었다. 신 축은 중복(P2≡P3, B=A+federation)을 제거하고 누락(AP2, AP3)을 채운다 → "6 이 맞나 4 가 맞나" 의 답: 둘은 다른 축이었고, keycloak 을 다 배우려면 auth 축 4패턴이 맞다.
3. 공통 컴포넌트 & 용어
- Keycloak: OIDC/OAuth2 Authorization Server. Realm / Client / User / Identity Provider 구성.
- Client (vanilla JS / SPA): Authorization Code Flow + PKCE. client 유형은 패턴별로 다름 — AP1 은 public client(토큰 브라우저 보유), AP2·AP3 은 백엔드가 confidential client(client secret 보유, 토큰을 백엔드가 획득). AP4 는 SPA 가 아니라 프록시가 OIDC client.
- Backend (API): Spring Boot. 패턴별 역할 상이 — AP1/AP4 는 Resource Server(JWT signature +
iss/aud/exp검증), AP2/AP3 는 confidential OAuth client(+ AP3 은 session holder + proxy). - Edge Proxy (P1만): oauth2-proxy 또는 Traefik ForwardAuth — 인증 안 된 요청을 Keycloak으로 redirect, 인증 완료 시 backend로 통과.
- IdP Brokering (B 변형): Keycloak이 Google을 외부 IdP로 등록. 사용자 Google 계정으로 로그인 → Google → Keycloak 사용자 매핑 (First Broker Login Flow) → Keycloak token 발급.
- Token 종류:
authorization code: 1회용 코드 (브라우저 redirect 매개)access token(JWT): API 호출용. 짧은 만료 (5–15분)refresh token: access token 갱신용. 긴 만료 (1–30일)ID token(JWT): 사용자 식별 정보. 백엔드는 보통 사용 안 함, 클라이언트가 사용자 표시용으로 사용.
3-1. 시스템 아키텍처 (System Architecture)
6개 패턴 각각의 컴포넌트 구성도.
templates/diagram-standards.mdv2 (minimalist) 준수 — 5초/30초 룰, 정점 ≤ 10, 간선 ≤ 8, callout ≤ 1, 80% 회색/흰색 + 강조 색 1~2 정도.작성 도구: draw.io (
.drawio파일, 저장 경로raw/diagrams/keycloak-patterns/). Mermaidgraph TD는 시스템 아키텍처용으로 사용 금지 — Mermaid 는 시퀀스/ER 다이어그램 전용.공통 시각 어휘 (모든 6 패턴 공통):
- 주황 box + 주황 굵은 화살 = 그 패턴의 주인공 (Edge proxy, tunnel, brokering 등)
- 파란 box + 파란 굵은 화살 = SPA-direct OIDC 또는 Keycloak brokering 핵심 경로
- 흰색 box + 회색 가는 화살 = 보조 컴포넌트 / 부차 경로
- 회색 점선 box = External system (Google OIDC 등)
- 빨간 callout = 그 패턴의 가장 큰 보안/운영 함정 (정확히 1개)
- ③, ④ 같은 번호 = 시각적 흐름 순서. 본문이 같은 번호로 받아 설명함.
3-1-1. P1A — Edge ForwardAuth (no Google)
!raw/diagrams/keycloak-patterns/architecture-p1a-edge-no-google-2026-05-26.drawio
다이어그램이 답하는 질문: edge proxy가 인증 게이트일 때, 백엔드는 어떻게 인증 코드 0줄로 동작하는가?
4단계 흐름 (다이어그램 ①~④):
① HTTPS(강조 — 진입 경로) — User browser 가 Edge zone 의 oauth2-proxy 에 요청② OIDC redirect— proxy 가 미인증 요청을 Keycloak 으로 redirect (Authorization Code + PKCE)③ 로그인 + token— Keycloak 로그인 UI 후 token 발급 (점선 = 사용자 매개 redirect)④ X-Forwarded-User(강조 — 핵심 위탁) — proxy 가 인증 사용자명을 헤더로 backend 에 전달
핵심 함정 (헤더 spoofing):
- backend 가
X-Forwarded-User헤더만으로 사용자 식별 → ingress 우회 경로 존재 시 위조 가능 - 해결: NetworkPolicy (k8s) 또는 SG (AWS) 로 proxy → backend 만 통과시키고, 가능하면 mTLS 추가
컴포넌트 책임 (P1A):
| 컴포넌트 | 역할 | 스택 |
|---|---|---|
| Edge Proxy | OIDC 인증 게이트 — 인증 안 된 요청을 Keycloak으로 redirect | oauth2-proxy 또는 Traefik ForwardAuth |
| Backend API | 비즈니스 로직만. 인증 검증은 proxy에 위임. 헤더로 사용자 식별 | Spring Boot 3.x (Spring Security 미사용) |
| Keycloak | Authorization Server. 사용자 DB + OIDC discovery | Keycloak 25.x + PostgreSQL 16 |
P1A 트레이드오프:
- 장점: backend 가 인증 코드 0줄. 다국적 polyglot 백엔드에 균일하게 인증 적용 용이.
- 단점: backend 가 헤더 신뢰 모델 → 네트워크 격리 실패 시 전면 우회.
출처 (Sources):
- oauth2-proxy ForwardAuth — raw/branch-notes/feature-keycloak-edge-forwardauth-no-google
- Traefik ForwardAuth — raw/branch-notes/feature-keycloak-edge-forwardauth-no-google
3-1-2. P1B — Edge ForwardAuth + Google federation
!raw/diagrams/keycloak-patterns/architecture-p1b-edge-google-2026-05-26.drawio
다이어그램이 답하는 질문: P1A 에 Google 로그인을 붙이면 Keycloak IdP brokering 만으로 SPA/Backend 변경 없이 가능한가?
5단계 흐름 (다이어그램 ①~⑤):
① HTTPS— User → oauth2-proxy② OIDC redirect— proxy → Keycloak (OIDC AS)③ Google 로그인(강조 — 외부 IdP 위탁 핵심) — Keycloak → Google OIDC④ id_token (email_verified)(점선 = 외부 호출) — Google → Keycloak, First Broker Login Flow 진입⑤ X-Forwarded-User— proxy → backend (P1A 와 동일)
핵심 함정 (First Broker Login Flow — email-match auto-linking):
- Keycloak 기본 옵션이 email 기반 자동 linking 제공
- Google 이
email_verified=false인 사용자도 통과시키면 본인 외 사용자의 기존 계정 탈취 가능 - 해결: First Broker Login Flow 에서
Confirm Link Existing Account강제 +email_verified=true필수
P1A 대비 추가/변화:
- Keycloak ← Google IdP brokering 설정 추가
- Backend / proxy 코드는 변경 0줄 — Keycloak Realm 설정만 추가
P1B 트레이드오프:
- 장점: SPA/Backend 코드 변경 0줄로 Google SSO 추가
- 단점: First Broker Login Flow 설정 실수 시 계정 탈취 위험. Google API 의존성 운영 부담.
출처 (Sources):
- Keycloak IdP brokering — raw/branch-notes/feature-keycloak-edge-forwardauth-google-federation
- First Broker Login Flow 보안 — raw/branch-notes/feature-keycloak-edge-forwardauth-google-federation
3-1-3. P2A — Cluster-internal SPA-direct (no Google)
!raw/diagrams/keycloak-patterns/architecture-p2a-cluster-internal-no-google-2026-05-26.drawio
다이어그램이 답하는 질문: Edge proxy 없이 SPA 가 직접 OIDC 할 때, Backend 는 어떻게 JWT 신뢰를 닫는가?
4단계 흐름 (다이어그램 ①~④):
① HTTPS GET (SPA)— User → nginx 가 호스팅하는 vanilla JS SPA 자원 수령② OIDC + PKCE(강조 — SPA 가 토큰 보유) — SPA → Keycloak, 직접 token 흐름 (P1 과의 결정적 차이)③ Bearer access_token(강조 — API 호출) — SPA → Backend,Authorization: Bearer ...④ JWKS(강조 — 신뢰 닫기) — Backend → Keycloak 에서 검증 공개키 조회
핵심 함정 (XSS surface):
- SPA 가 access/refresh token 을 브라우저 메모리/스토리지에 보유 → XSS 1건 = 세션 전체 탈취
- 해결: refresh token 보호가 필요하면 BFF(P1) 로 전환, 또는 httpOnly cookie 전략 검토
P1A 대비 차이:
- SPA 가 토큰 직접 보유 → XSS surface ↑, BFF 패턴 검토 가치 있음
- Backend 가 JWT validator 코드 보유 (
iss,aud,exp, signature) — Spring Security 6.x Resource Server
P2A 트레이드오프:
- 장점: 컴포넌트 단순 (proxy 1개 제거). frontend 가 OIDC 흐름 완전 제어 가능.
- 단점: XSS surface 확대 + backend 가 JWT 검증 코드 보유 → polyglot 백엔드 마다 구현 필요.
출처 (Sources):
- Spring Security Resource Server — raw/branch-notes/feature-keycloak-internal-spa-direct-no-google
- PKCE 흐름 (RFC 7636) — raw/branch-notes/feature-keycloak-internal-spa-direct-no-google
3-1-4. P2B — Cluster-internal + Google federation
!raw/diagrams/keycloak-patterns/architecture-p2b-cluster-internal-google-2026-05-26.drawio
다이어그램이 답하는 질문: P2A 에 Google brokering 을 추가할 때, SPA/Backend 코드는 그대로 둘 수 있는가?
5단계 흐름 (다이어그램 ①~⑤):
① HTTPS GET— User → nginx SPA② OIDC + PKCE— SPA → Keycloak (P2A 와 동일)③ Google 로그인(강조 — 외부 IdP 위탁) — Keycloak → Google④ id_token(점선 = 외부 호출) — Google → Keycloak, First Broker Login Flow⑤ Bearer + JWKS— SPA → Backend (Bearer), Backend → Keycloak (JWKS)
핵심 함정 (P1B + P2A 중첩):
- P1B 의 email-match auto-linking + P2A 의 SPA XSS surface 가 모두 적용됨
- 해결:
Confirm Link Existing Account강제 +email_verified=true+ 클라이언트 CSP / sanitize 강화 / 필요 시 BFF(P1) 로 이주
P2A 대비 추가/변화:
- Keycloak Realm 에 Google IdP 등록만 추가 (SPA/Backend 변경 0줄)
- First Broker Login Flow 보안 옵션 추가 검토 필요
P2B 트레이드오프:
- 장점: SPA/Backend 코드 0줄 변경으로 Google SSO 추가
- 단점: 두 함정 (auto-linking + XSS) 가 중첩되어 보안 운영 부담 ↑
출처 (Sources):
- Keycloak IdP brokering — raw/branch-notes/feature-keycloak-internal-spa-direct-google-federation
- First Broker Login Flow 보안 — raw/branch-notes/feature-keycloak-internal-spa-direct-google-federation
3-1-5. P3A — Single EC2 (no Google) — 실 구현 대상
!raw/diagrams/keycloak-patterns/architecture-p3a-single-ec2-no-google-2026-05-26.drawio
다이어그램이 답하는 질문: 사용자 요청이 어떤 컴포넌트를 어떤 순서로 거치며 인증되는가?
5단계 흐름 (다이어그램 ①~⑤):
① HTTPS GET /— User browser 가 nginx 에서 SPA 정적 자원 받음② OIDC + PKCE(강조 — 핵심 경로) — Browser 가 Keycloak 으로 직접 redirect, Authorization Code + PKCE 흐름③ Bearer token + /api— SPA 가 받은 access_token 으로 API 호출④ proxy_pass— nginx 가 Spring Boot 로 reverse proxy⑤ JWKS(강조 — 검증 경로) — Spring Boot 가 Keycloak 에서 JWT 검증 키 조회
핵심 함정 (KC_HOSTNAME):
- Browser 는 EC2 public hostname 으로 Keycloak 호출 → JWT 의
issclaim = public host - Backend 는
localhost:8180로 JWKS 조회 →iss비교 시 mismatch → 401 - 해결: docker-compose 에
KC_HOSTNAME=<public-host>+KC_HTTP_ENABLED=true명시
부차 함정 (redirect_uri):
- Keycloak client 의 Valid Redirect URIs 등록 시
localhost만 등록 / browser 가127.0.0.1접근 → mismatch - 해결: 등록과 접근 hostname 1:1 일치 또는 둘 다 등록
P3A 트레이드오프:
- 장점: 학습 / 개발 환경 최단 셋업. 단일 docker-compose 로 끝남.
- 단점: SPoF — EC2 1대 다운 = 전체 정지. 운영급은 P2A + Keycloak HA cluster.
출처 (Sources):
- KC_HOSTNAME 함정 — raw/branch-notes/feature-keycloak-iss-claim-hostname-mismatch
- redirect_uri 함정 — raw/branch-notes/feature-keycloak-docker-compose-stack
- OIDC PKCE — raw/official-docs/oauth2-pkce-rfc-7636 (또는 해당 official-doc)
다이어그램 편집: Obsidian draw.io 플러그인으로 위 임베드 더블클릭. 또는 draw.io 데스크탑 앱 사용.
3-1-6. P3B — Single EC2 + Google federation
!raw/diagrams/keycloak-patterns/architecture-p3b-single-ec2-google-2026-05-26.drawio
다이어그램이 답하는 질문: P3A 에 Google 을 붙이려면 왜 외부 HTTPS endpoint(tunnel/RP) 가 강제되는가?
6단계 흐름 (다이어그램 ①~⑥):
① HTTPS(강조 — 공개 진입) — User → HTTPS tunnel (cloudflared / ngrok / Caddy)② localhost (HTTP)(강조 — tunnel 가 localhost 위탁) — tunnel → nginx③ proxy_pass /api— nginx → Spring Boot Backend④ JWKS— Backend → Keycloak 검증 키 조회⑤ Google 로그인 (공개 HTTPS)(강조 — 외부 IdP) — Keycloak → Google⑥ id_token(점선 = 외부 호출) — Google → Keycloak
핵심 함정 (KC_HOSTNAME 공개 hostname 강제):
- Google 이 검증하는
redirect_uri와 Keycloak issuer 가 모두 공개 HTTPS host 여야 함 - P3A 처럼
localhost로 설정 시 Google 흐름 실패 또는 issuer 불일치 401 - 해결:
KC_HOSTNAME=<public-host>+ Keycloak Realm Client 의Valid Redirect URIs를 public URL 로
P3A 대비 추가 요구사항: EC2 를 외부 HTTPS 로 노출 (Google 이 redirect_uri 검증). cloudflared / ngrok / 정식 도메인 + Caddy 중 택일.
P3B 트레이드오프:
- 장점: P3A 단순성을 유지하면서 Google SSO 추가 가능
- 단점: tunnel/RP 운영 부담 + KC_HOSTNAME 설정 함정 (P3A 의 함정이 hostname 만 바뀌어 재발)
출처 (Sources):
- KC_HOSTNAME 함정 — raw/branch-notes/feature-keycloak-single-ec2-google-federation
- cloudflared / ngrok 비교 — raw/branch-notes/feature-keycloak-single-ec2-google-federation
3-1-7. AP2 (Token-Mediating) · AP3 (BFF) — needs-diagram
신 primary 축의 AP2·AP3 은 기존 6
.drawio(P1A~P3B = AP1 배포 변형 + AP4)에 대응 아키텍처 다이어그램이 없다. needs-diagram — 사용자가 draw.io 로 작성 후 아래 백틱을 풀어 활성 임베드로 전환한다. (미작성 파일을 활성 임베드로 두면 9a 린터가BROKEN_LINK로 잡으므로 placeholder 는 백틱 코드로 비활성.)
- AP2 Token-Mediating Backend:
![[raw/diagrams/keycloak-patterns/architecture-ap2-token-mediating-2026-07-14.drawio.svg]] - AP3 Backend-for-Frontend:
![[raw/diagrams/keycloak-patterns/architecture-ap3-bff-2026-07-14.drawio.svg]]
작성 시 rules/diagram-standards.md v2 (minimalist) 준수 + wiki-diagram-reviewer ≥95 별도 확인(게이트는 존재만 판정, 품질 ≥95 는 사용자가 별도 실행).
3-2. 핵심 시퀀스 (Key Sequences — Mermaid)
토큰 교환 흐름은 패턴마다 다름. happy path + 주요 error path 함께.
templates/project-template.md§4 표준 준수 —autonumber,actorvsparticipant구분, alt/opt/loop 블록,Note over비자명한 동작.
P3A: vanilla JS + PKCE + Keycloak (단일 EC2, no Google)
sequenceDiagram
autonumber
actor User
participant SPA as vanilla JS SPA (nginx)
participant KC as Keycloak (Authorization Server)
participant API as Spring Boot Resource Server
User->>SPA: 로그인 클릭
SPA->>SPA: PKCE code_verifier 생성, code_challenge=SHA256(verifier)
SPA->>KC: GET /realms/<realm>/protocol/openid-connect/auth?client_id=<spa>&response_type=code&code_challenge=...&redirect_uri=...
KC-->>User: 로그인 폼 redirect
User->>KC: id/password 입력
alt 자격 증명 유효
KC-->>SPA: 302 redirect with authorization code
SPA->>KC: POST /token (code + code_verifier)
KC-->>SPA: 200 OK {access_token, id_token, refresh_token}
SPA->>API: GET /api/v1/<resource> + Authorization: Bearer <access_token>
API->>API: JWT 검증 (iss, aud, exp, signature with JWKS)
alt JWT 유효
API-->>SPA: 200 OK {resource}
SPA-->>User: 화면 표시
else aud claim mismatch
API-->>SPA: 401 Unauthorized {error: invalid_token}
SPA-->>User: 에러 + 재로그인 유도
end
else 자격 증명 무효
KC-->>SPA: 302 redirect with error=access_denied
SPA-->>User: 에러 표시
end
위 P3A 시퀀스 = AP1(SPA-direct + Resource Server)의 single-EC2 배포. 아래는 나머지 3 패턴의 핵심 시퀀스(happy + error path).
AP2: Token-Mediating Backend (백엔드 confidential client, access token 만 브라우저 전달)
sequenceDiagram
autonumber
actor User
participant B as Browser (SPA)
participant BE as Backend (confidential client)
participant KC as Keycloak
participant API as Resource API
User->>B: 로그인 클릭
B->>BE: GET /login
BE->>KC: Authorization Code (confidential client + secret)
KC-->>User: 로그인 폼
User->>KC: 자격 증명
alt 로그인 성공
KC-->>BE: access_token + refresh_token
Note over BE: refresh_token 은 백엔드만 보유 (브라우저 미전달)
BE-->>B: access_token 만 전달
B->>API: GET /resource + Bearer access_token
API-->>B: 200 OK
else access_token 만료 (재발급은 백엔드 경유)
API-->>B: 401 invalid_token
B->>BE: POST /token/refresh
BE->>KC: refresh_grant (백엔드 보유 refresh_token)
KC-->>BE: 새 access_token
BE-->>B: 새 access_token
end
AP3: Backend-for-Frontend (BFF) — 토큰 0개, session cookie 만
sequenceDiagram
autonumber
actor User
participant B as Browser (SPA)
participant BFF as BFF (Spring oauth2Login)
participant KC as Keycloak
participant API as Resource API
User->>B: 로그인 클릭
B->>BFF: GET /oauth2/authorization/keycloak
BFF->>KC: Authorization Code (confidential client)
KC-->>User: 로그인 폼
User->>KC: 자격 증명
alt 로그인 성공
KC-->>BFF: 302 + authorization code
BFF->>KC: POST /token (code + client_secret)
KC-->>BFF: access/refresh token (BFF session 에 저장)
BFF-->>B: Set-Cookie: SESSION (httpOnly) — 브라우저에 토큰 없음
B->>BFF: GET /api/resource (cookie 자동 첨부)
BFF->>API: GET /resource + Bearer (BFF 가 토큰 부착)
API-->>BFF: 200 OK
BFF-->>B: 200 OK
else CSRF (cookie 자동첨부 악용)
Note over B,BFF: 외부 사이트가 cookie 실린 상태변경 요청 위조
BFF-->>B: 403 (SameSite=Lax + CSRF token 검증 실패로 차단)
end
Gateway forward-auth (oauth2-proxy, 백엔드 인증코드 0줄)
sequenceDiagram
autonumber
actor User
participant Proxy as oauth2-proxy (ForwardAuth)
participant KC as Keycloak
participant API as Backend API
User->>Proxy: GET /app (미인증)
Proxy->>KC: OIDC redirect (Authorization Code + PKCE)
KC-->>User: 로그인 폼
User->>KC: 자격 증명
alt 인증 성공
KC-->>Proxy: token (proxy session 보관)
Proxy->>API: GET /app + X-Forwarded-User: <sub>
API-->>Proxy: 200 OK (헤더만으로 사용자 식별)
Proxy-->>User: 200 OK
else 헤더 위조 우회 시도 (signature 함정)
Note over API: ingress 우회 경로로 X-Forwarded-User 직접 주입
API-->>User: 200 (❌ network 격리 실패 시 위조 성공)
Note over API: 방어 = NetworkPolicy/SG 로 proxy→API 만 통과 (+ mTLS)
end
P2B → AP4/AP1 + Google: Google IdP federation 추가 흐름 (sub-branch에 상세)
(Google brokering 은 AP1~AP4 어디에도 코드 0줄로 얹히는 cross-cutting. 상세 다이어그램은 각 sub-branch — raw/branch-notes/feature-keycloak-edge-forwardauth-google-federation, raw/branch-notes/feature-keycloak-internal-spa-direct-google-federation — 에서.)
4. 인프라 / 기술 스택
| 영역 | 선택 |
|---|---|
| 언어 | Java 21 (Backend), JavaScript ES2022+ (vanilla, no framework) |
| 프레임워크 | Spring Boot 3.x + Spring Security 6.x (Resource Server) |
| Authorization Server | Keycloak 25.x (latest stable as of 2026-05) |
| DB (Keycloak) | PostgreSQL 16 |
| Web Server (SPA) | nginx (static file serving) |
| 컨테이너 | Docker + Docker Compose |
| 배포 환경 (P3A 한정) | 단일 EC2 (학습용) — HTTPS termination 선택적 |
| OIDC client library | 직접 PKCE 구현 또는 oidc-client-ts |
5. 작업 범위 (Project-level Scope)
포함 범위 (2026-07-14 교정 — 4 인증-아키텍처 패턴 실 구현)
- 4 인증-아키텍처 패턴(AP1~AP4) 실 구현 — 모두 single-EC2 로컬 스택 위에서 E2E(
locally-verified) + signature 함정 재현→해결 (§1 성공기준, §8.0 branch 분해). - Google IdP brokering 을 cross-cutting 변형으로 1회 실 구현(어느 패턴에 얹어도 SPA/Backend 코드 0줄 변경 검증 포함).
- 4 패턴 통합 trade-off 매트릭스 (토큰 위치 / 검증 주체 / XSS·CSRF surface / 선택 기준 / keycloak 설정).
- 각 패턴의 공식 문서 · 기술블로그 출처 raw 보존 + 채택/대안/비교 구조 명시.
- 각 패턴에서 토큰 종류의 교환 시점 · 저장 위치 · 만료 정책 정리.
제외 범위
- 배포 토폴로지 별도 구현: 인증 아키텍처는 single-EC2 로 실 구현하고, cluster-internal / edge 는 hostname·issuer·network 차이만 문서화(별도 k8s/Traefik 환경 구축 안 함 — §2.2 cross-cutting).
- 다른 OIDC Provider(GitHub / Auth0 / Cognito) federation. Google만.
- React/Vue 등 SPA 프레임워크 (vanilla JS 유지).
- 모바일 / 네이티브 앱 흐름 (PKCE for native).
- mTLS, FAPI(Financial-grade API), DPoP 등 고급 보안 옵션.
Deferred — keycloak SERVER-side 심화 트랙 (2026-07-14 명시, 지금 안 함)
사용자 확정: 4 client-integration 패턴 E2E 를 먼저 끝낸 뒤 별도 학습 트랙으로 착수. "keycloak 다 알기" 의 나머지 절반(server/운영 측면)이며, 본 프로젝트 현 phase 의 out-of-scope 이되 폐기가 아니라 후속 트랙으로 예약한다.
- SPI (Service Provider Interface) — custom authenticator / mapper / event listener 작성.
- HA cluster — Infinispan 분산 캐시, active-active Keycloak 다중 노드.
- multi-realm / 멀티테넌시 — realm-per-tenant vs client-per-tenant.
- Admin REST API 자동화 — realm/client export·import 를 코드로 (
feature-keycloak-realm-client-export씨앗 존재). - LDAP / user federation — 외부 사용자 저장소 연동.
- token revocation 심화 — JWT stateless 한계 + blacklist / introspection endpoint.
인접 관심사 커버리지 note (9-coverage — silent 누락 방지):
- 인가(Authorization) — keycloak roles → Spring
@PreAuthorize: 본 4 패턴은 authN(인증) 토큰 흐름에 집중한다. RBAC 인가는 별개 관심사이며 기존 씨앗feature-keycloak-idp-mappers-claim-to-role존재 — 4 패턴 E2E 후 각 패턴에 얹음(현 phase 명시적 out-of-scope, 폐기 아님). - Logout / session termination (front/back-channel): AP3 BFF session 종료 · AP1 토큰 만료로 부분 커버. refresh rotation + logout 후 session·token 무효화는
WI-KEYCLOAK-PATTERNS-OVERVIEW-007(feature-keycloak-refresh-rotation-and-logout, §8.0 registry)이 현 phase 로 커버한다. 통합 front/back-channel logout 흐름 심화만 deferred (2026-07-23 경계 명확화 — §8.0 WI-007 과의 이중 서술 해소).
기술 결정
Legacy reference (v1). 아래 비교표는 rationale과 대안을 보존한다. stable decision owner와 branch 상속 기준은 §6.1 registry다.
프로젝트 차원 기술 결정. 각 결정은 검토한 대안 + 외부근거 wikilink 필수 (근거 없으면
UNSUPPORTED_DECISION). 결정별 깊은 대안 비교는 branch 단계(/branch-spec+wiki-decision-researcher)로 위임 — 본 표는 hub 차원 stack/축 결정의 근거 소싱까지.
| 결정 영역 | 선택 | 검토한 대안 | 채택 이유 | 트레이드오프 | 근거 자료 |
|---|---|---|---|---|---|
| 분류 primary 축 | 인증 통합 아키텍처 4패턴 (AP1~AP4) | (a) 배포×federation 6패턴(기존) (b) IETF 3패턴만 (c) 멘토 "4패턴" | 6축은 auth 아키텍처 2종만 exercise + AP2/AP3 누락. IETF 3 + edge-proxy = 4 가 keycloak client 통합 canonical 축이며 중복(P2≡P3, B=A+federation) 제거 + 누락(AP2·AP3) 채움 | edge-proxy(AP4)는 IETF 3종 밖 실무 확장 — 표준 인용은 IETF 3까지만 유효 | raw/official-docs/oauth2-browser-based-apps-ietf-draft, raw/company-tech-blogs/curity-bff-pattern-spa |
| AP1 SPA client 유형 | public client + Authorization Code + PKCE | implicit flow / password grant | implicit·password 는 OAuth 2.1 에서 사실상 배제. PKCE 가 public client 표준 | 토큰이 브라우저에 노출(XSS surface) — AP2/AP3 로 완화 가능 | raw/official-docs/oauth2-pkce-rfc-7636, raw/official-docs/oauth-v2-1-draft-ietf |
| AP3 BFF 토큰 위치 | 백엔드 session (브라우저 = cookie 만) | 브라우저 저장 (localStorage / memory) | "토큰을 브라우저 밖에 두는 것이 XSS 로부터 보호하는 유일한 방법"(Curity) — 최고 보안강도 | stateful(session store 필요), 모바일 별도 흐름, CSRF surface 증가 | raw/company-tech-blogs/curity-bff-pattern-spa, raw/official-docs/oauth2-browser-based-apps-ietf-draft |
| AP2 Token-Mediating Backend | 백엔드 confidential client 가 토큰 획득, access token 만 브라우저 전달 | AP1(전부 브라우저) / AP3(전부 백엔드) | BFF 보다 경량(모든 요청 proxy 불필요) + AP1 보다 refresh token 보호 | access token 은 여전히 브라우저 노출 | raw/official-docs/oauth2-browser-based-apps-ietf-draft |
| AP4 Edge forward-auth | oauth2-proxy ForwardAuth | Traefik ForwardAuth / nginx auth_request / Spring Cloud Gateway TokenRelay |
백엔드 인증코드 0줄, polyglot 균일 적용 | 헤더 신뢰 모델 → network 격리 실패 시 전면 우회 | raw/official-docs/oauth2-proxy-keycloak-oidc-provider-official, raw/official-docs/oauth2-proxy-nginx-integration-official |
| Google federation | Keycloak IdP brokering + First Broker Login hardening | SPA/Backend 가 직접 Google OIDC 호출 | keycloak 이 brokering 흡수 → 앱 코드 0줄. First Broker Login 으로 account linking 제어 | email auto-linking 계정탈취 위험 → Confirm Link Existing Account 필수 | raw/official-docs/keycloak-identity-brokering-overview-official, raw/official-docs/keycloak-first-broker-login-flow |
소싱 bound(회당 6): 위 6개로 마감. 추가 결정(HTTPS termination D2~D5 등)은 §13 에 기존 근거 보존, deferred server-side 트랙 결정은 후속
/project-spec회차로 이월(deferred).
프로젝트 레벨 고정 결정 (Fixed Decisions — branch 간 충돌 방지)
Legacy reference (v1). F1~F5의 현재 stable owner는 아래 §6.1 registry다. F1은 taxonomy decision에 병합하며 중복 owner row를 만들지 않는다.
여러 branch 가 공유하므로 hub 가 1회 고정. branch 는 재정의 금지, 본 절을 참조만 (SSOT).
| # | 고정 결정 | SSOT 위치 | 이유 / 충돌 방지 |
|---|---|---|---|
| F1 | 인증 패턴 taxonomy = §2 (AP1~AP4 + cross-cutting) | §2 (본 노트) | 모든 branch 는 §2 의 AP-ID 를 인용. 패턴을 branch 에서 재정의하면 6-vs-4 혼선 재발 |
| F2 | done-bar = E2E + signature 함정 재현→해결 | §1 성공기준 | 4 패턴 branch 가 동일 완료 기준 상속. 등급은 src/ 검증 후 locally-verified |
| F3 | 단일 공유 realm keycloak-patterns, 패턴당 client 1개 (spa-public / token-mediating-confidential / bff-confidential / edge-proxy) |
§4 스택 + baseline branch | client 분리로 aud claim 충돌 방지. AP1 audience validator 가 client별 aud 검증 가능 |
| F4 | confidential client secret = env var, 미커밋 | baseline branch | AP2·AP3 는 client secret 보유. .env/KC_* 로 주입, realm export JSON 에 평문 금지 |
| F5 | E2E 실 구현 배포 = single-EC2 docker-compose (cluster-internal/edge 는 문서만) | §2.2, §5 | 배포 토폴로지는 cross-cutting 이라 auth 아키텍처를 바꾸지 않음 — 실 구현 1벌로 4 패턴 모두 검증 |
6.1 안정 결정 레지스트리
| Decision ID | Revision | Domain | Decision Summary | Status | Owner | Evidence |
|---|---|---|---|---|---|---|
DEC-KEYCLOAK-PATTERNS-OVERVIEW-AUTH-TAXONOMY-001 |
1 | auth-taxonomy |
canonical 분류축은 AP1~AP4 인증 통합 아키텍처와 cross-cutting 변형이다 | active |
raw/project-notes/keycloak-patterns-overview | §2; §기술 결정 분류 primary 축; F1 |
DEC-KEYCLOAK-PATTERNS-OVERVIEW-SPA-CLIENT-001 |
1 | spa-client |
AP1은 public client와 Authorization Code + PKCE를 사용한다 | active |
raw/project-notes/keycloak-patterns-overview | §기술 결정 AP1 SPA client 유형; raw/official-docs/oauth2-pkce-rfc-7636 |
DEC-KEYCLOAK-PATTERNS-OVERVIEW-BFF-SESSION-001 |
1 | bff-session |
AP3는 token을 backend session에 두고 browser에는 cookie만 둔다 | active |
raw/project-notes/keycloak-patterns-overview | §기술 결정 AP3 BFF 토큰 위치; raw/official-docs/oauth2-browser-based-apps-ietf-draft |
DEC-KEYCLOAK-PATTERNS-OVERVIEW-TOKEN-MEDIATING-001 |
1 | token-mediating |
AP2 backend가 token을 획득하고 access token만 browser에 전달한다 | active |
raw/project-notes/keycloak-patterns-overview | §기술 결정 AP2 Token-Mediating Backend; raw/official-docs/oauth2-browser-based-apps-ietf-draft |
DEC-KEYCLOAK-PATTERNS-OVERVIEW-EDGE-FORWARDAUTH-001 |
1 | edge-forwardauth |
AP4는 oauth2-proxy ForwardAuth를 사용한다 | active |
raw/project-notes/keycloak-patterns-overview | §기술 결정 AP4 Edge forward-auth; raw/official-docs/oauth2-proxy-keycloak-oidc-provider-official |
DEC-KEYCLOAK-PATTERNS-OVERVIEW-IDP-BROKERING-001 |
1 | idp-brokering |
Google federation은 Keycloak IdP brokering과 hardened First Broker Login을 사용한다 | active |
raw/project-notes/keycloak-patterns-overview | §기술 결정 Google federation; raw/official-docs/keycloak-first-broker-login-flow |
DEC-KEYCLOAK-PATTERNS-OVERVIEW-ACCEPTANCE-001 |
1 | acceptance |
done-bar는 E2E success와 signature security failure 재현·해결 evidence다 | documented-only |
raw/project-notes/keycloak-patterns-overview | F2; §1 성공 기준 |
DEC-KEYCLOAK-PATTERNS-OVERVIEW-REALM-CLIENT-001 |
1 | realm-client |
단일 realm keycloak-patterns에서 인증 패턴별 client를 분리한다 | documented-only |
raw/project-notes/keycloak-patterns-overview | F3; §4 stack |
DEC-KEYCLOAK-PATTERNS-OVERVIEW-SECRET-BOUNDARY-001 |
1 | secret-boundary |
confidential client secret은 env var로 주입하고 commit·realm export 평문을 금지한다 | documented-only |
raw/project-notes/keycloak-patterns-overview | F4 |
DEC-KEYCLOAK-PATTERNS-OVERVIEW-DEPLOYMENT-001 |
1 | deployment |
AP1~AP4 E2E 구현 topology는 single-EC2 docker-compose다 | documented-only |
raw/project-notes/keycloak-patterns-overview | F5; §2.2; §5 |
8.0 실행계획
| Work Item ID | branch slug | 완료 조건 (측정가능) | Applies Decisions | Dependencies | Status |
|---|---|---|---|---|---|
WI-KEYCLOAK-PATTERNS-OVERVIEW-001 |
feature-keycloak-docker-compose-stack |
Keycloak·PostgreSQL·nginx·Spring 4 containers가 healthy이고 admin console에 접속된다 | DEC-KEYCLOAK-PATTERNS-OVERVIEW-DEPLOYMENT-001@1 |
- | planned |
WI-KEYCLOAK-PATTERNS-OVERVIEW-002 |
feature-keycloak-realm-client-export |
realm import와 client 4개 등록 후 unauthenticated protected endpoint가 401이고 export가 재현된다 | DEC-KEYCLOAK-PATTERNS-OVERVIEW-REALM-CLIENT-001@1, DEC-KEYCLOAK-PATTERNS-OVERVIEW-SECRET-BOUNDARY-001@1 |
WI-KEYCLOAK-PATTERNS-OVERVIEW-001 |
planned |
WI-KEYCLOAK-PATTERNS-OVERVIEW-003 |
feature-keycloak-vanilla-js-spa-pkce |
vanilla JS PKCE login·token 수령·protected API 200이 재현된다 | DEC-KEYCLOAK-PATTERNS-OVERVIEW-SPA-CLIENT-001@1, DEC-KEYCLOAK-PATTERNS-OVERVIEW-ACCEPTANCE-001@1 |
WI-KEYCLOAK-PATTERNS-OVERVIEW-002 |
planned |
WI-KEYCLOAK-PATTERNS-OVERVIEW-004 |
feature-keycloak-spring-rs-audience-validator |
foreign audience token 수용 실패를 재현하고 validator 적용 후 401을 검증한다 | DEC-KEYCLOAK-PATTERNS-OVERVIEW-SPA-CLIENT-001@1, DEC-KEYCLOAK-PATTERNS-OVERVIEW-ACCEPTANCE-001@1 |
WI-KEYCLOAK-PATTERNS-OVERVIEW-003 |
planned |
WI-KEYCLOAK-PATTERNS-OVERVIEW-005 |
feature-keycloak-iss-claim-hostname-mismatch |
hostname 미설정 iss mismatch 401과 설정 후 복구 log가 존재한다 | DEC-KEYCLOAK-PATTERNS-OVERVIEW-SPA-CLIENT-001@1, DEC-KEYCLOAK-PATTERNS-OVERVIEW-ACCEPTANCE-001@1 |
WI-KEYCLOAK-PATTERNS-OVERVIEW-003 |
planned |
WI-KEYCLOAK-PATTERNS-OVERVIEW-006 |
feature-keycloak-spa-token-storage-tradeoff |
저장 위치별 browser token read/XSS surface가 재현되고 선택이 기록된다 | DEC-KEYCLOAK-PATTERNS-OVERVIEW-SPA-CLIENT-001@1 |
WI-KEYCLOAK-PATTERNS-OVERVIEW-003 |
planned |
WI-KEYCLOAK-PATTERNS-OVERVIEW-007 |
feature-keycloak-refresh-rotation-and-logout |
refresh rotation과 logout 후 session·token 무효화가 검증된다 | DEC-KEYCLOAK-PATTERNS-OVERVIEW-SPA-CLIENT-001@1, DEC-KEYCLOAK-PATTERNS-OVERVIEW-ACCEPTANCE-001@1 |
WI-KEYCLOAK-PATTERNS-OVERVIEW-004 |
planned |
WI-KEYCLOAK-PATTERNS-OVERVIEW-008 |
feature-keycloak-token-mediating-confidential-client |
confidential backend의 code-token 교환과 server-side refresh 보관이 검증된다 | DEC-KEYCLOAK-PATTERNS-OVERVIEW-TOKEN-MEDIATING-001@1, DEC-KEYCLOAK-PATTERNS-OVERVIEW-SECRET-BOUNDARY-001@1 |
WI-KEYCLOAK-PATTERNS-OVERVIEW-002 |
in-progress |
WI-KEYCLOAK-PATTERNS-OVERVIEW-009 |
feature-keycloak-token-mediating-access-handoff |
browser가 access token으로 API 200을 받고 refresh token은 network response에 존재하지 않는다 | DEC-KEYCLOAK-PATTERNS-OVERVIEW-TOKEN-MEDIATING-001@1, DEC-KEYCLOAK-PATTERNS-OVERVIEW-ACCEPTANCE-001@1 |
WI-KEYCLOAK-PATTERNS-OVERVIEW-008 |
in-progress |
WI-KEYCLOAK-PATTERNS-OVERVIEW-010 |
feature-keycloak-bff-oauth2login-session |
browser token 0개와 SESSION cookie만으로 BFF proxy API 200이 재현된다 | DEC-KEYCLOAK-PATTERNS-OVERVIEW-BFF-SESSION-001@1, DEC-KEYCLOAK-PATTERNS-OVERVIEW-SECRET-BOUNDARY-001@1 |
WI-KEYCLOAK-PATTERNS-OVERVIEW-002 |
in-progress |
WI-KEYCLOAK-PATTERNS-OVERVIEW-011 |
feature-keycloak-bff-csrf-samesite-defense |
CSRF를 재현하고 SameSite와 CSRF token 적용 후 403을 검증한다 | DEC-KEYCLOAK-PATTERNS-OVERVIEW-BFF-SESSION-001@1, DEC-KEYCLOAK-PATTERNS-OVERVIEW-ACCEPTANCE-001@1 |
WI-KEYCLOAK-PATTERNS-OVERVIEW-010 |
in-progress |
WI-KEYCLOAK-PATTERNS-OVERVIEW-012 |
feature-keycloak-oauth2-proxy-oidc-flow |
unauthenticated redirect와 login 후 X-Forwarded-User backend 200이 재현된다 | DEC-KEYCLOAK-PATTERNS-OVERVIEW-EDGE-FORWARDAUTH-001@1, DEC-KEYCLOAK-PATTERNS-OVERVIEW-ACCEPTANCE-001@1 |
WI-KEYCLOAK-PATTERNS-OVERVIEW-002 |
planned |
WI-KEYCLOAK-PATTERNS-OVERVIEW-013 |
feature-keycloak-nginx-auth-request-integration |
nginx auth_request 통합과 4KB cookie split case가 검증된다 | DEC-KEYCLOAK-PATTERNS-OVERVIEW-EDGE-FORWARDAUTH-001@1 |
WI-KEYCLOAK-PATTERNS-OVERVIEW-012 |
planned |
WI-KEYCLOAK-PATTERNS-OVERVIEW-014 |
feature-keycloak-header-spoofing-defense |
forwarded-user spoofing 우회를 재현하고 network isolation 후 차단한다 | DEC-KEYCLOAK-PATTERNS-OVERVIEW-EDGE-FORWARDAUTH-001@1, DEC-KEYCLOAK-PATTERNS-OVERVIEW-ACCEPTANCE-001@1 |
WI-KEYCLOAK-PATTERNS-OVERVIEW-012 |
planned |
WI-KEYCLOAK-PATTERNS-OVERVIEW-015 |
feature-keycloak-idp-brokering-google-client |
Google login·Keycloak user mapping 200과 application diff 0줄이 검증된다 | DEC-KEYCLOAK-PATTERNS-OVERVIEW-IDP-BROKERING-001@1 |
WI-KEYCLOAK-PATTERNS-OVERVIEW-003 |
planned |
WI-KEYCLOAK-PATTERNS-OVERVIEW-016 |
feature-keycloak-first-broker-login-flow |
unsafe auto-linking을 재현하고 Confirm Link Existing Account로 차단한다 | DEC-KEYCLOAK-PATTERNS-OVERVIEW-IDP-BROKERING-001@1, DEC-KEYCLOAK-PATTERNS-OVERVIEW-ACCEPTANCE-001@1 |
WI-KEYCLOAK-PATTERNS-OVERVIEW-015 |
planned |
WI-KEYCLOAK-PATTERNS-OVERVIEW-017 |
feature-keycloak-google-claim-attribute-mapping |
Google email·name claim이 Keycloak attribute로 매핑된다 | DEC-KEYCLOAK-PATTERNS-OVERVIEW-IDP-BROKERING-001@1 |
WI-KEYCLOAK-PATTERNS-OVERVIEW-015 |
planned |
WI-KEYCLOAK-PATTERNS-OVERVIEW-018 |
feature-keycloak-account-linking-sub-vs-email |
sub와 email linking key의 security comparison과 선택이 기록된다 | DEC-KEYCLOAK-PATTERNS-OVERVIEW-IDP-BROKERING-001@1 |
WI-KEYCLOAK-PATTERNS-OVERVIEW-016 |
planned |
WI-KEYCLOAK-PATTERNS-OVERVIEW-019 |
feature-keycloak-four-pattern-tradeoff-matrix |
4패턴 비교표의 모든 cell이 구현 WI evidence를 가리킨다 | DEC-KEYCLOAK-PATTERNS-OVERVIEW-AUTH-TAXONOMY-001@1, DEC-KEYCLOAK-PATTERNS-OVERVIEW-ACCEPTANCE-001@1 |
WI-KEYCLOAK-PATTERNS-OVERVIEW-003, WI-KEYCLOAK-PATTERNS-OVERVIEW-008, WI-KEYCLOAK-PATTERNS-OVERVIEW-010, WI-KEYCLOAK-PATTERNS-OVERVIEW-012 |
in-progress |
WI-KEYCLOAK-PATTERNS-OVERVIEW-020 |
feature-keycloak-patterns |
project governance hub가 AP1~AP4 taxonomy와 child progress index를 유지한다 | DEC-KEYCLOAK-PATTERNS-OVERVIEW-AUTH-TAXONOMY-001@1 |
- | in-progress |
실행계획 (Branch decomposition, R4)
Legacy reference (v1). 아래 2-tier grouping과 priority 설명은 보존한다. Tier-1은 파일이 아닌 group label이며 stable branch ID·decision pin·dependency의 SSOT는 위 Work Item Registry다.
/project-spec핸드오프 섹션. 2-tier — Tier-1 = 패턴 parent(project 직접 자식,parent_branch:비어있음), Tier-2 = 실제 "1 branch = 1 PR" 단위(각 Tier-2 가 "1개로 끝낼 양"). 각 branch 의 네이밍 + 측정가능 목표조건 + 우선순위 + 의존만 적는다 — 결정 내용·메커니즘은/branch <slug>생성 후/branch-spec가 깊게 채운다. slug 는rules/naming-conventions.md§2.1 준수(feature-+ content-descriptive, numbered hierarchy 없음). 규모: 7 Tier-1 / 19 Tier-2 ≈ 19 PR — "바로 끝낼 양" 아님(수 주 분량). 기존 27 sub-sub-branch 를 4-패턴으로 re-map + AP2 만 신규.
Tier-1 개요 (7 parent)
| Tier-1 parent slug | 역할 | Tier-2 수 | 우선순위 |
|---|---|---|---|
feature-keycloak-local-stack-baseline |
4 패턴 공유 로컬 스택 | 2 | P1 |
feature-keycloak-spa-direct-resource-server |
AP1 | 5 | P2 |
feature-keycloak-token-mediating-backend |
AP2 (신규) | 2 | P3 |
feature-keycloak-bff-session-proxy |
AP3 | 2 | P3 |
feature-keycloak-edge-forwardauth-proxy |
AP4 | 3 | P3 |
feature-keycloak-google-idp-brokering |
Google cross-cutting | 4 | P4 |
feature-keycloak-four-pattern-tradeoff-matrix |
종합 매트릭스 | 1 | P5 |
명명 정합 (2026-07-14 감사 — 파일 ↔ hub 매칭 검증):
- Tier-2 실 구현 19개: 14개 = 기존 branch-note 파일과 슬러그 정확히 일치 ✓. 5개 = 신규 예정(
token-mediating-confidential-client·-access-handoff,bff-oauth2login-session·-csrf-samesite-defense,four-pattern-tradeoff-matrix) →/branch로 생성.- Tier-1 그룹명 7개는 파일이 아니라 그룹 라벨이다(파일로 만들면 기존 pattern 노트 §12.1 와 중복되므로 만들지 않음). 각 Tier-2 의 물리적
parent_branch:는 현재 옛 pattern 노트(§12.1)를 가리키고, AP 그룹 소속은 본 분해표가 SSOT. 링크 깨짐 0.- 재-parent 매핑(각 그룹 실 작업 착수 시
wiki-doc-author mode=migrate로 반영 — 지금은 cosmetic 이라 미실행): Google Tier-2 4개(현 parent P1Bedge-forwardauth-google-federation) → Google 그룹,spring-rs-audience-validator·spa-token-storage-tradeoff(현 parent P2Ainternal-spa-direct-no-google) → AP1 그룹. 나머지는 현 parent 가 이미 AP anchor(single-ec2/edge)와 정합.
그룹 0 — 공유 baseline (parent feature-keycloak-local-stack-baseline)
| Tier-2 sub-branch | 달성 목표 조건 (측정가능) | 우선순위 | 의존 |
|---|---|---|---|
feature-keycloak-docker-compose-stack |
docker compose up → Keycloak+PostgreSQL+nginx+Spring 4 컨테이너 healthy + KC admin 콘솔 접속 |
P1 | - |
feature-keycloak-realm-client-export |
realm keycloak-patterns import + client 4개(spa-public / token-mediating-confidential / bff-confidential / edge-proxy) 등록 + 보호 endpoint 토큰없이 401 + JSON export 재현 |
P1 | feature-keycloak-docker-compose-stack |
그룹 1 — AP1 SPA-direct + Resource Server (parent feature-keycloak-spa-direct-resource-server)
| Tier-2 sub-branch | 달성 목표 조건 (측정가능) | 우선순위 | 의존 |
|---|---|---|---|
feature-keycloak-vanilla-js-spa-pkce |
vanilla JS 가 PKCE(code_verifier/challenge)로 로그인 → access_token 수령 → /api 200 |
P2 | baseline |
feature-keycloak-spring-rs-audience-validator |
Spring RS 가 JWKS 검증 + aud 미검증 → 타 client 토큰 통과 재현 → audience validator 로 401 |
P2 | feature-keycloak-vanilla-js-spa-pkce |
feature-keycloak-iss-claim-hostname-mismatch |
KC_HOSTNAME 미설정 → iss mismatch 401 재현 → 설정으로 해결(로그 before/after) |
P2 | feature-keycloak-vanilla-js-spa-pkce |
feature-keycloak-spa-token-storage-tradeoff |
저장위치별 XSS surface 시연(JS 에서 토큰 read 가능 재현) + 저장 전략 결정 기록 | P3 | feature-keycloak-vanilla-js-spa-pkce |
feature-keycloak-refresh-rotation-and-logout |
refresh rotation 동작 + 로그아웃 시 세션/토큰 무효화 확인 | P3 | feature-keycloak-spring-rs-audience-validator |
그룹 2 — AP2 Token-Mediating Backend (parent feature-keycloak-token-mediating-backend) — 신규
| Tier-2 sub-branch | 달성 목표 조건 (측정가능) | 우선순위 | 의존 |
|---|---|---|---|
feature-keycloak-token-mediating-confidential-client |
백엔드(confidential client)가 code→token 교환 성공(client_secret) + refresh 를 서버 세션 보관 | P3 | baseline |
feature-keycloak-token-mediating-access-handoff |
access_token 만 브라우저 전달 → 브라우저가 RS 직접 호출 200 + refresh 가 네트워크탭/응답 바디에 부재 확인 |
P3 | feature-keycloak-token-mediating-confidential-client |
그룹 3 — AP3 BFF (parent feature-keycloak-bff-session-proxy)
| Tier-2 sub-branch | 달성 목표 조건 (측정가능) | 우선순위 | 의존 |
|---|---|---|---|
feature-keycloak-bff-oauth2login-session |
Spring oauth2Login 로그인 → 브라우저 토큰 0개(SESSION cookie 만) + BFF proxy 경유 API 200 |
P3 | baseline |
feature-keycloak-bff-csrf-samesite-defense |
cookie 자동첨부 CSRF 재현 → SameSite + CSRF token 으로 403 차단 |
P3 | feature-keycloak-bff-oauth2login-session |
그룹 4 — AP4 Edge forward-auth (parent feature-keycloak-edge-forwardauth-proxy)
| Tier-2 sub-branch | 달성 목표 조건 (측정가능) | 우선순위 | 의존 |
|---|---|---|---|
feature-keycloak-oauth2-proxy-oidc-flow |
oauth2-proxy 앞단 → 미인증 redirect → 인증 후 backend X-Forwarded-User 200 |
P3 | baseline |
feature-keycloak-nginx-auth-request-integration |
nginx auth_request 통합 동작 + 4kb cookie 분할 함정 확인 |
P3 | feature-keycloak-oauth2-proxy-oidc-flow |
feature-keycloak-header-spoofing-defense |
X-Forwarded-User 위조 우회 재현 → network 격리(SG/NetworkPolicy)로 차단 |
P3 | feature-keycloak-oauth2-proxy-oidc-flow |
(감사 정정 2026-07-14)
feature-keycloak-traefik-forwardauth-alternative은 impl branch 아님 — 본문이 스스로 "선택 기준 정리까지만" 이고 P3A 는 nginx+oauth2-proxy 채택. FOLD-IN(비교 근거)으로 강등, 아래 fold-in 목록 참조.
그룹 5 — Google IdP brokering cross-cutting (parent feature-keycloak-google-idp-brokering)
| Tier-2 sub-branch | 달성 목표 조건 (측정가능) | 우선순위 | 의존 |
|---|---|---|---|
feature-keycloak-idp-brokering-google-client |
realm 에 Google IdP 등록 → Google 계정 로그인 → Keycloak 사용자 매핑 200 + SPA/Backend diff 0줄 검증 |
P4 | AP1 group |
feature-keycloak-first-broker-login-flow |
email_verified=false auto-linking 계정탈취 재현 → Confirm Link Existing Account 로 차단 |
P4 | feature-keycloak-idp-brokering-google-client |
feature-keycloak-google-claim-attribute-mapping |
Google claim → Keycloak attribute 매핑(email/name) 확인 | P4 | feature-keycloak-idp-brokering-google-client |
feature-keycloak-account-linking-sub-vs-email |
계정 linking 키 sub vs email 보안 비교 → 결정 기록 |
P4 | feature-keycloak-first-broker-login-flow |
그룹 6 — 종합 (parent 없음, 최종)
| Tier-2 sub-branch | 달성 목표 조건 (측정가능) | 우선순위 | 의존 |
|---|---|---|---|
feature-keycloak-four-pattern-tradeoff-matrix |
4 패턴을 {토큰 위치 · 검증 주체 · XSS/CSRF surface · 선택 기준 · keycloak 설정} 열로 한 표에 정리 + 각 셀이 구현 branch 검증 증거 link | P5 | AP1~AP4 4개 group |
기존 sub-branch 흡수/승격: 위 Tier-2 대부분은 기존 27 sub-sub-branch(§12.1 legacy)의 실 구현 승격이다. 예외 — 학습노트로 fold-in(별도 impl branch 아님):
feature-keycloak-pkce-flow-stages·feature-keycloak-spring-rs-role-mapping·feature-keycloak-refresh-token-rotation(→ AP1 그룹 근거),feature-keycloak-bff-vs-spa-direct(→ AP3 비교 근거),feature-keycloak-traefik-forwardauth-alternative(→ AP4 비교 근거, P3A 는 nginx+oauth2-proxy 채택),feature-keycloak-federation-spa-zero-change·feature-keycloak-three-leg-trust-chain·feature-keycloak-account-linking-spa-ux(→ Google 그룹 근거). AP2 그룹 2개(신규)만 완전 신규 파일. 실제 파일 rename/re-parent 는wiki-doc-author mode=migrate로 점진(자동 mv 금지).배포 토폴로지 sub-branch 는 documentation-only(F5):
feature-keycloak-public-domain-tunneling·feature-keycloak-reverse-proxy-headers·feature-keycloak-https-termination-caddy-nginx·feature-keycloak-google-redirect-uri-policy는 single-EC2 실 구현 밖 배포 변형이라 §13 HTTPS termination 근거로 문서만 유지(별도 impl branch 아님). 인가(RBAC)feature-keycloak-idp-mappers-claim-to-role는 §5 deferred(authZ)로 이월.중복 정합 완료 (2026-07-14 감사 — 각 파일에 정합 노트 삽입): (1)
spring-rs-role-mapping↔spring-rs-audience-validator— Spring RS 셋업·aud검증은 audience-validator 가 owner, role-mapping 의 role→RBAC 부분만 deferred authZ. (2)idp-mappers-claim-to-role↔google-claim-attribute-mapping— attribute-mapping 은 google-claim-attribute-mapping 이 owner, idp-mappers 의 claim→role 부분만 deferred authZ. (확인된 비-중복: account-linking sub-vs-email↔spa-ux, federation-spa-zero-change↔three-leg-trust-chain, refresh 2개 — 상호보완이라 유지.)
6. 본인이 한 작업 (사실만)
각 항목 옆에 증거 등급 표기:
가능한 등급: actually-implemented | locally-verified | prod-verified | documented-only | planned | needs-confirmation
- 6 패턴 분류 축 정의 (배치 × federation) — 등급:
documented-only(2026-07-14 인증 아키텍처 4패턴으로 축 교정됨 — 아래 참조) - 6 sub-branch 작성 (목표 / 다이어그램 / 토큰 sequence / 장단점) — 등급:
documented-only - 28 raw 외부 자료 보존 (공식 문서 + 기술블로그) — 등급:
documented-only - 분류축 교정 + hub §2 재편 (2026-07-14): 배치×federation 6패턴 → 인증 아키텍처 4패턴(AP1~AP4) primary + cross-cutting. 측정가능 성공기준(§1)·기술결정 소싱표(6/6)·Branch 분해표(7 branch) 추가. IETF browser-based-apps raw 보존 — 등급:
documented-only - AP1
AP4 실 구현 (코드) — 등급:3)planned(Branch 분해표 Phase 2
7. 마주친 문제 / 트러블슈팅
Phase 1(문서화) 단계에서 발견한 함정. Phase 2(P3A 실 구현) 시 마주칠 가능성 높음.
-
iss claim mismatch (단일 EC2):
- 원인: Keycloak
KC_HOSTNAME미설정 시 browser와 backend가 다른 hostname을 보고, JWTissclaim이 mismatch → backend JWT validation 실패. - 해결:
KC_HOSTNAME=<hostname>+KC_HTTP_ENABLED=true명시. browser/backend 모두 같은 issuer 사용.
- 원인: Keycloak
-
Spring Security
audclaim 미검증 (default):- 원인: Spring Security 기본 JWT validator는
iss,exp만 검증,aud검증 안 함. 다른 client용 토큰이 본 backend로 흘러들 위험. - 해결: custom
OAuth2TokenValidator<Jwt>로aud=<expected-client-id>검증 추가.
- 원인: Spring Security 기본 JWT validator는
-
redirect_uri mismatch (localhost vs 127.0.0.1):
- 원인: Keycloak client 설정의
Valid Redirect URIs에localhost만 등록했는데 browser가127.0.0.1로 접근 (또는 반대). - 해결: 등록과 사용 hostname을 1:1 일치시키거나 둘 다 등록.
- 원인: Keycloak client 설정의
-
Google First Broker Login Flow의 email-match auto-linking 보안 위험:
- 원인: 기본 First Broker Login Flow가 email 기반 자동 linking 옵션 제공. 그러나 Google이 email_verified=false 인 사용자 통과 가능 → 본인 외 사용자의 기존 계정 탈취 가능.
- 해결: First Broker Login Flow에 "Confirm Link Existing Account" + email_verified=true 강제 + manual confirm.
8. 자신 없는 부분
면접에서 받을 가능성이 있지만 본인이 확실히 답할 수 없는 영역. P3A 구현 + Phase 3 sub-sub-branch 학습 후 보강 예정.
- BFF (Backend-for-Frontend) 패턴 실 구현 경험 부재 — 문서만 봤음
- Keycloak SPI (Service Provider Interface)로 custom IdP 작성
- 운영 환경에서 token revocation 처리 (JWT 자체는 stateless, blacklist 필요 시)
- Keycloak multi-realm 운영 (테넌트별 realm 분리 vs 단일 realm + client별 분리)
- HTTPS termination 위치 (nginx vs Caddy vs ALB) trade-off
- Keycloak 자체의 HA 구성 (Infinispan + cluster)
9. 관련 자료
- 저장소 URL:
/home/donghyeon/workspace/keycloak-patterns/(별도 git repo, 아직 비어 있음 — Phase 2 진입 시 생성) - 관련 PR / 커밋: 없음
- canonical SSOT (본 문서): raw/project-notes/keycloak-patterns-overview
10. 진행 단계 (Phase)
| Phase | 내용 | 상태 |
|---|---|---|
| Phase 0 | 배치×federation 6패턴 정의 + 34 branch-note + 6 .drawio + 외부자료 보존 |
✅ 2026-05-27 완료 |
| Phase 1 | 분류축 교정: 인증 아키텍처 4패턴(AP1~AP4) 재편 + 측정가능 성공기준(§1) + 기술결정 소싱(6/6) + Branch 분해표(7 branch) | ✅ 2026-07-14 완료 |
| Phase 2 | feature-keycloak-local-stack-baseline + AP1 |
⏳ Pending |
| Phase 3 | Google IdP brokering cross-cutting + 4패턴 trade-off 매트릭스 (Branch 분해표 P4~P5) | ⏳ Pending |
| Phase 4 | AP1~AP4 locally-verified 승급 + wiki/projects/keycloak-patterns/ 추출 |
⏳ Pending |
| Phase 5 (deferred) | keycloak server-side 심화 트랙 (SPI / HA / multi-realm / LDAP — §5 Deferred) | ⏳ Deferred |
11. wiki 추출 정책
- Phase 4 완료 시점에 추출: P3A의
actually-implemented/locally-verified항목만wiki/projects/keycloak-patterns/로 추출. - 추출하지 않음: P1A/P1B/P2A/P2B/P3B는
documented-only유지, wiki/projects 승급 안 함. 단, 학습 노트 가치가 있으면 별도wiki/concepts/keycloak-deployment-patterns.md로 합성 검토 (Phase 4 이후).
12. 묶음 (이 프로젝트에 묶이는 모든 raw 자료)
- raw/company-tech-blogs/curity-bff-pattern-spa
- raw/company-tech-blogs/keycloak-google-login-codemancers
- raw/company-tech-blogs/keycloak-jwt-role-extraction-betweendata
- raw/official-docs/aws-alb-target-security-group-restriction-official
- raw/official-docs/aws-cloudfront-origin-shared-secret-header-official
- raw/official-docs/aws-security-group-referencing-official
- raw/official-docs/chrome-third-party-cookie-policy-google-official
- raw/official-docs/cloudflare-tunnel-routing-official
- raw/official-docs/docker-compose-depends-on-healthcheck
- raw/official-docs/docker-compose-networking-extra-hosts-official
- raw/official-docs/docker-engine-20-10-release-notes-official
- raw/official-docs/docker-host-network-driver-official
- raw/official-docs/docker-port-publishing-loopback-bind-official
- raw/official-docs/google-oauth-app-verification-state-overview-official
- raw/official-docs/google-oauth-manage-app-audience-official
- raw/official-docs/google-oauth2-client-application-types-official
- raw/official-docs/google-oauth2-policies-environment-separation-official
- raw/official-docs/google-oauth2-redirect-uri-validation-official
- raw/official-docs/google-oauth2-web-server-flow-official
- raw/official-docs/google-oidc-discovery-spec
- raw/official-docs/google-openid-connect-oidc
- raw/official-docs/istio-mtls-cert-rotation-official
- raw/official-docs/k8s-network-policy-official
- raw/official-docs/keycloak-2500-hostname-v2-release-official
- raw/official-docs/keycloak-2600-hostname-v1-removed-official
- raw/official-docs/keycloak-account-console-unlink-lockout-guard-official
- raw/official-docs/keycloak-client-initiated-account-linking
- raw/official-docs/keycloak-client-pkce-method-enforcement-official
- raw/official-docs/keycloak-configuring-database
- raw/official-docs/keycloak-first-broker-login-flow
- raw/official-docs/keycloak-first-broker-login-verify-authenticators-official
- raw/official-docs/keycloak-first-login-flow
- raw/official-docs/keycloak-getting-started-docker
- raw/official-docs/keycloak-google-idp-setup
- raw/official-docs/keycloak-health-checks
- raw/official-docs/keycloak-hostname-configuration
- raw/official-docs/keycloak-identity-broker-spi
- raw/official-docs/keycloak-identity-brokering-overview-official
- raw/official-docs/keycloak-identity-provider-mappers
- raw/official-docs/keycloak-identity-provider-redirector-default-idp-official
- raw/official-docs/keycloak-identity-provider-sync-mode-official
- raw/official-docs/keycloak-identity-provider-trust-email-official
- raw/official-docs/keycloak-idp-hide-on-login-page-toggle-official
- raw/official-docs/keycloak-idp-hint-client-suggested-official
- raw/official-docs/keycloak-import-export-realms
- raw/official-docs/keycloak-oidc-logout-endpoint-official
- raw/official-docs/keycloak-refresh-token-rotation-reuse-admin-official
- raw/official-docs/keycloak-refresh-token-rotation-sessions-official
- raw/official-docs/keycloak-reverseproxy-official
- raw/official-docs/keycloak-securing-apps-overview-official
- raw/official-docs/keycloak-server-containers-docker
- raw/official-docs/nginx-auth-request-module-official
- raw/official-docs/nginx-core-module-location-internal-official
- raw/official-docs/ngrok-http-tunnel-official
- raw/official-docs/oauth-v2-1-draft-ietf
- raw/official-docs/oauth2-browser-based-apps-ietf-draft
- raw/official-docs/oauth2-pkce-rfc-7636
- raw/official-docs/oauth2-proxy-behaviour-cookie-vs-bearer-official
- raw/official-docs/oauth2-proxy-cookie-redirect-flags-official
- raw/official-docs/oauth2-proxy-endpoints-official
- raw/official-docs/oauth2-proxy-endpoints-signout-official
- raw/official-docs/oauth2-proxy-keycloak-oidc-provider-official
- raw/official-docs/oauth2-proxy-nginx-integration-official
- raw/official-docs/oauth2-proxy-overview-config-official
- raw/official-docs/oauth2-proxy-session-storage-official
- raw/official-docs/oauth2-token-revocation-rfc-7009
- raw/official-docs/oidc-client-ts-library
- raw/official-docs/openid-connect-core-id-token-validation
- raw/official-docs/owasp-html5-storage-xss-spa
- raw/official-docs/proxy-pass-request-body-nginx-official
- raw/official-docs/security-jwt-rfc-7519-validation
- raw/official-docs/silent-check-sso-third-party-cookies-keycloak-official
- raw/official-docs/spring-security-authorization-defense-in-depth
- raw/official-docs/spring-security-authorize-http-requests
- raw/official-docs/spring-security-method-security
- raw/official-docs/spring-security-nested-authorities-claim-issue-15201
- raw/official-docs/spring-security-resource-server-jwt
- raw/official-docs/third-party-cookie-blocking-safari-webkit-official
- raw/official-docs/traefik-forwardauth-middleware-official
- raw/official-docs/traefik-hub-oidc-middleware-official
- raw/official-docs/traefik-oidc-community-plugin-lukaszraczylo-official
본 project-note는 cluster의 entry point. 모든 branch / sources / errors / interviews / lectures 가 여기로 upward link. hub 측에서도 카테고리별 명시.
12.1 브랜치
- raw/branch-notes/feature-keycloak-account-linking-sub-vs-email
- raw/branch-notes/feature-keycloak-bff-csrf-samesite-defense
- raw/branch-notes/feature-keycloak-bff-oauth2login-session
- raw/branch-notes/feature-keycloak-docker-compose-stack
- raw/branch-notes/feature-keycloak-first-broker-login-flow
- raw/branch-notes/feature-keycloak-four-pattern-tradeoff-matrix
- raw/branch-notes/feature-keycloak-google-claim-attribute-mapping
- raw/branch-notes/feature-keycloak-header-spoofing-defense
- raw/branch-notes/feature-keycloak-idp-brokering-google-client
- raw/branch-notes/feature-keycloak-iss-claim-hostname-mismatch
- raw/branch-notes/feature-keycloak-nginx-auth-request-integration
- raw/branch-notes/feature-keycloak-oauth2-proxy-oidc-flow
- raw/branch-notes/feature-keycloak-patterns
- raw/branch-notes/feature-keycloak-realm-client-export
- raw/branch-notes/feature-keycloak-refresh-rotation-and-logout
- raw/branch-notes/feature-keycloak-spa-token-storage-tradeoff
- raw/branch-notes/feature-keycloak-spring-rs-audience-validator
- raw/branch-notes/feature-keycloak-token-mediating-access-handoff
- raw/branch-notes/feature-keycloak-token-mediating-confidential-client
- raw/branch-notes/feature-keycloak-vanilla-js-spa-pkce
generated reverse view는 child branch의 v2 contract migration 후 채운다. 아래 수기 legacy inventory는 그 전까지 navigation으로 보존한다.
⚠️ Legacy inventory (구 6패턴 축). 아래 목록은 Phase 0 의 배치×federation 구조다. 현 실행계획은 "Branch 분해 / 실행계획 (R4)" 표 — 아래 branch 들은 §2.3 매핑대로 AP1~AP4 로 re-map/승격 대상(실제 rename 은
wiki-doc-author mode=migrate). 신규 작업 진입점은 분해표를 따른다. Root branch + 6개 Tier-2 sub-branches + 27개 Tier-3 sub-sub-branches.
- Root: raw/branch-notes/feature-keycloak-patterns — 전체 진행 인덱스 hub
- Tier-2 sub-branches (구 6 패턴 → §2.3 매핑: P1x→AP4, P2x/P3x→AP1):
- raw/branch-notes/feature-keycloak-edge-forwardauth-no-google — P1A Edge / Ingress (no Google)
- raw/branch-notes/feature-keycloak-edge-forwardauth-google-federation — P1B Edge / Ingress + Google federation
- raw/branch-notes/feature-keycloak-internal-spa-direct-no-google — P2A Cluster-internal SPA-direct (no Google)
- raw/branch-notes/feature-keycloak-internal-spa-direct-google-federation — P2B Cluster-internal + Google federation
- raw/branch-notes/feature-keycloak-single-ec2-no-google — P3A Single EC2 (no Google) — 실 구현 대상
- raw/branch-notes/feature-keycloak-single-ec2-google-federation — P3B Single EC2 + Google federation
- Tier-3 sub-sub-branches (각 패턴 4~6개): root branch raw/branch-notes/feature-keycloak-patterns 의 Cluster 섹션 참조.
12.2 근거 자료 (프로젝트 전체 차원 foundational 조사)
- 개별 official-doc / company-tech-blog 들은 각 sub-branch 의 Sources 표에서 cited.
- raw/official-docs/oauth2-browser-based-apps-ietf-draft — IETF draft-ietf-oauth-browser-based-apps-27. 4-패턴 인증 아키텍처 taxonomy(§2.1) 가 준거로 삼는 업계 표준 3대 아키텍처(BFF / Token-Mediating Backend / Browser-based OAuth Client, decreasing order of security) 정의의 foundational 근거. AP4(edge forward-auth)만 IETF 3종 밖 실무 확장.
12.3 오류 기록 (branch 외 발생한 환경·운영 이슈)
- (없음 — Phase 3 P3A 구현 진입 시 발생 예상)
12.4 면접 준비
- (없음 — sub-branch 별로 면접 후보 누적 후 별도 raw/interviews/ 신설 예정)
12.5 강의
- (없음 — 필요 시 Keycloak Summit / OIDC 강의 추가)
12.6 파생 wiki 문서
- canonical 검증 사실: (없음 — Phase 4 시
wiki/projects/keycloak-patterns/신설) - 관련 일반 개념: (없음 — Phase 4 이후
wiki/concepts/keycloak-deployment-patterns.md검토) - 포트폴리오: (없음)
- 블로그 글: (없음)
13. Phase 5 Additional Evidence Raws (2026-05-27)
Phase 5B 외부 근거 추가 보강. HTTPS termination 결정 (P3B 의 tunnel/RP 선택, §3-1-6 의 cloudflared / ngrok / Caddy 비교) 영역에 5개 신규 raw 파일 (
raw/official-docs/하위) 추가. 각 raw 는 frontmatterrelated_projects: [keycloak-patterns]보유.출처 신뢰도 (CLAUDE.md §5 정합): 모두
source_type: official-doc(IETF RFC, OWASP cheat sheet, vendor 공식 reference). company-tech-blog 없음.사용 경계: 본 섹션은 raw evidence 의 cluster-level index. 각 raw 의 정확한 Claim ID / Usage Boundary 는 raw 파일 자체의
## Claims Extracted섹션 참조. 본 project-note 는 owning sub-branch 에 매핑할 뿐, raw 의 verbatim claim 을 그대로 keycloak best practice 로 단정하지 않음.
13.1 HTTPS Termination / TLS Policy (5 raw)
P3B (Single EC2 + Google federation) 의 HTTPS termination 결정 — Google IdP 가 검증하는 redirect_uri 와 Keycloak issuer 가 모두 공개 HTTPS host 여야 함 (§3-1-6 핵심 함정 KC_HOSTNAME). 아래 5개 raw 가 termination 전략 선택지 (D2~D5) 의 외부 근거.
| raw | 채택 위치 (decision / sub-branch) | 사용 근거 |
|---|---|---|
| raw/official-docs/rfc8996-tls10-tls11-deprecation | https-termination D5 (TLS 버전 policy), raw/branch-notes/feature-keycloak-single-ec2-google-federation | RFC 8996 (TLS 1.0/1.1 Deprecation, IETF 2021) 이 P3B 의 HTTPS termination (tunnel/RP 어느 쪽이든) 이 최소 TLS 1.2+ 강제 해야 하는 baseline. Google OIDC discovery endpoint 도 TLS 1.2+ 요구. |
| raw/official-docs/owasp-hsts-cheat-sheet | https-termination D5 (HSTS header policy), raw/branch-notes/feature-keycloak-single-ec2-google-federation | OWASP HSTS Cheat Sheet 가 Strict-Transport-Security header 의 baseline (max-age, includeSubDomains, preload). Caddy / Certbot+nginx / Cloudflare tunnel 어느 termination 도 HSTS 활성화 해야 함. preload 진입 결정은 branch-note 에서 별도 trade-off. |
| raw/official-docs/caddy-automatic-https-docs | https-termination D2 (Caddy option), raw/branch-notes/feature-keycloak-single-ec2-google-federation | Caddy 공식 "Automatic HTTPS" doc. P3B termination 선택지 중 정식 도메인 + Caddy 옵션 — Caddy 가 ACME (Let's Encrypt / ZeroSSL) 자동 발급·갱신·OCSP stapling 을 기본 제공. 트레이드오프: 단일 binary, config 간결성 vs nginx 운영 표준성. |
| raw/official-docs/certbot-user-guide | https-termination D3 (Certbot + nginx option), raw/branch-notes/feature-keycloak-single-ec2-google-federation | Certbot 공식 user guide. P3B termination 선택지 중 정식 도메인 + nginx + Certbot 옵션 — Certbot 이 Let's Encrypt ACME 클라이언트의 reference 구현. cron/systemd timer 기반 갱신, nginx plugin 의 in-place reload. 트레이드오프: 운영 표준성 (nginx) vs config 분리도 (Caddy 대비). |
| raw/official-docs/aws-acm-managed-renewal | https-termination D4 (AWS ALB/CloudFront option), raw/branch-notes/feature-keycloak-single-ec2-google-federation | AWS ACM Managed Renewal 공식 reference. P3B termination 선택지 중 AWS ALB / CloudFront 앞단 옵션 — ACM 이 publicly trusted cert 의 13개월 자동 갱신을 platform-side 에서 책임. EC2 내부 (Keycloak) 는 HTTP 또는 self-signed 로 충분. 트레이드오프: AWS lock-in vs 운영 부담 zero. |
비교 매트릭스 (4개 termination option):
| 옵션 | cert 발급 자동화 | 인프라 위치 | lock-in | P3B 적합도 |
|---|---|---|---|---|
| cloudflared tunnel | Cloudflare 측 | 외부 (no inbound) | Cloudflare | 학습/dev 최적 (가장 가벼움) |
| Caddy + 도메인 | Caddy 자체 (ACME) | EC2 내 | none (open source) | 단일 binary, prod 가능 |
| nginx + Certbot + 도메인 | Certbot (cron) | EC2 내 | none | 운영 표준 (가장 친숙) |
| AWS ALB/CloudFront + ACM | ACM 자동 | AWS platform | AWS | prod 권장 (운영 부담 최소) |
Out of scope (P3B termination 선택 후 별도 분기): mTLS termination, FAPI 준수 termination, EV cert, multi-domain SAN, custom CA. ngrok 은 학습용 short-lived tunnel 로 cloudflared 대안 (별도 raw 미수집).
14. 아키텍처 검토 체크리스트 (작성/갱신 시 self-check)
- 한 줄 요약 + 현재 상태 + 나의 역할 채워짐 (§1)
- 측정 가능한 성공 기준 1개 이상 — §1 성공 기준(측정가능, R1) 추가 (2026-07-14): 4 패턴 각각 E2E
200+ signature 함정 재현→해결, done-bar 정량화 완료. ✓ - 아키텍처 다이어그램 1개 이상 첨부 (§3-1) — 기존 6
.drawio(2026-05-26, minimalist) ✓. 단 신 축 AP2·AP3 은 needs-diagram (§3-1-7) — 사용자 작성 대기. - 다이어그램의 모든 컴포넌트가 라벨 + 역할 표기 ✓
- 다이어그램의 모든 화살표가 프로토콜·데이터 종류 라벨링 ✓
- 외부 시스템이 점선 + 회색으로 시각적 구분 ✓ (Google OIDC = dashed gray box)
- 범례(Legend) 다이어그램 내부 + §3-1 도입부에 포함 ✓
- 신뢰 경계 / 네트워크 경계 표시 ✓ (Edge zone / Internal / EC2 / Public HTTPS)
- 시퀀스 다이어그램 1개 이상 (Mermaid) — happy path + error path 함께 (§3-2 P3A) ✓
- Cluster 섹션의 root branch 목록 채워짐 (§12.1) ✓
- 마지막 architecture review 날짜 frontmatter
architecture_review:에 기록 — 2026-05-26 ✓