28 KiB
title, source_type, status, id, kind, project, work_item, inherits, refines, overrides, depends_on, contract_packet, branch, parent_branch, related_projects, tags, created, target_merge, status_label, contract_packet_sha256
| title | source_type | status | id | kind | project | work_item | inherits | refines | overrides | depends_on | contract_packet | branch | parent_branch | related_projects | tags | created | target_merge | status_label | contract_packet_sha256 | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| branch / feature-keycloak-bff-vs-spa-direct (BFF 대안 비교 — SPA Direct vs Backend-for-Frontend) | branch-note | raw | BR-KEYCLOAK-CHILD-2BFCDCAB | branch-child | keycloak-patterns-overview | WI-KEYCLOAK-PATTERNS-OVERVIEW-020 |
|
1 | feature-keycloak-bff-vs-spa-direct | feature-keycloak-patterns |
|
|
2026-05-25 | in-progress | f0b2fdad99f29c8e633580dc9d5b65c5b88879f90ace63f773a6ded847306d5f |
branch: feature-keycloak-bff-vs-spa-direct — BFF 대안 비교
Layer:
raw/branch-notes/— raw/branch-notes/feature-keycloak-patterns의 branch-child. 목적: P2A(SPA Direct, 토큰을 SPA가 보유) vs BFF(Backend-for-Frontend, 토큰을 백엔드가 보유)의 XSS surface 차이와 stateful trade-off를 명확히 정리.status_label:in-progress|review|merged|abandoned
부모 (필수)
raw/branch-notes/feature-keycloak-patterns
브랜치 계약 패킷
- 생성 시 프로젝트 개정:
1 - 패킷 스키마:
contract_packet: 1 - 완료 조건: project governance hub가 AP1~AP4 taxonomy와 child progress index를 유지한다
상속한 프로젝트 결정
| Decision Ref | Project Summary | Branch Application | Source |
|---|---|---|---|
DEC-KEYCLOAK-PATTERNS-OVERVIEW-AUTH-TAXONOMY-001@1 |
canonical 분류축은 AP1~AP4 인증 통합 아키텍처와 cross-cutting 변형이다 | SPA Direct와 BFF 비교를 AP taxonomy의 대안 근거로 유지한다 | raw/project-notes/keycloak-patterns-overview |
브랜치 지역 결정
| Decision ID | Decision | Relation | Supporting Claims | Status |
|---|---|---|---|---|
| D1 | 학습 baseline은 SPA Direct로 둔다 | local |
raw/project-notes/keycloak-patterns-overview | proposed |
| D2 | BFF 구현은 비교 문서 범위로 제한한다 | local |
raw/project-notes/keycloak-patterns-overview | proposed |
| D3 | native client는 별도 PKCE 흐름이 필요함을 기록한다 | local |
raw/project-notes/keycloak-patterns-overview | proposed |
| D4 | browser token XSS surface를 BFF motivation으로 기록한다 | local |
raw/project-notes/keycloak-patterns-overview | proposed |
| D5 | BFF 권고의 적용 조건을 client credential 사용 여부로 제한한다 | local |
raw/project-notes/keycloak-patterns-overview | proposed |
선언한 예외
| Override ID | Overrides | Reason | Approval | Status |
|---|
없음.
목표
P2A SPA Direct는 OIDC + PKCE의 canonical 흐름이지만 토큰이 브라우저(JS 컨텍스트)에 존재한다는 근본적 위험이 있다. BFF는 이 위험을 제거하는 변형 — 백엔드가 OAuth client 역할을 하고, 브라우저는 httpOnly session cookie만 보유. Curity 등 보안 벤더가 권고하는 패턴.
핵심 질문:
- BFF 아키텍처에서 토큰이 흐르는 경계는? 누가 보관하는가?
- Spring Security
oauth2Login+ session vs Spring Authorization Server (AS 자체 구축) 차이? - BFF 단점은? (stateful, scale-out 시 session sharing 필요)
- 어떤 기준으로 SPA Direct vs BFF를 결정하는가? (XSS 민감도 / 모바일 클라이언트 유무 / 운영 복잡도)
본 sub-sub-branch는 아키텍처 다이어그램 + Spring 구현 옵션 + 결정 기준 매트릭스를 정리.
- 이슈: (학습 노트, 이슈 없음)
- PR: (구현 없음)
범위
포함 범위
- BFF(Backend-for-Frontend)와 SPA Direct(P2A)의 XSS surface 차이 정리 — 토큰이 브라우저(JS 컨텍스트)에 있는가 vs 백엔드에 있는가의 경계
- BFF 아키텍처 다이어그램 + 토큰 흐름 경계(누가 access/refresh token holder 인가)
- Spring Security
oauth2Login(BFF) 구현 옵션의 사전 명세 —documented-only(실 구현 아님, §구현 가이드) - SPA Direct vs BFF 결정 기준 매트릭스 — "언제 어느 패턴" 선택 조건 (XSS 민감도 / 모바일 클라이언트 유무 / 백엔드 stateless / 운영 복잡도 / revocation 즉시성 / OAuth 2.1의 client-credentials 조건부 권고)
- Curity(company-tech-blog) + OAuth 2.1 draft(official-standard) 인용으로 BFF motivation 근거화
제외 범위
의도적으로 제외한 것. 면접 등에서 "이건 범위에 없었습니다"라고 답할 근거.
- BFF 실 구현/배포 — 문서화만.
documented-only유지(D2). P3A 실 구현 이후 XSS 민감 요구 발생 시 별도 확장 branch - Spring Authorization Server (AS 자체 구축) — Keycloak 대체 프로젝트로 BFF 결정과 직교. Keycloak을 AS로 두고
oauth2Login만으로 BFF 성립하므로 본 학습 범위 밖 - P1A Edge ForwardAuth 상세 — 형제 raw/branch-notes/feature-keycloak-edge-forwardauth-no-google 소관 (본 branch는 BFF와의 개념 구분만)
- SPA Direct 토큰 저장 위치 상세 — 형제 raw/branch-notes/feature-keycloak-spa-token-storage-tradeoff 소관
- refresh token rotation/revocation 상세 — 형제 raw/branch-notes/feature-keycloak-refresh-token-rotation 소관
- 모바일/native OAuth client 실 흐름 — RFC 8252 public-client PKCE 흐름 자체의 구현. 본 branch는 "BFF가 모바일을 커버 못 함"의 한계 명시까지만(D3)
근거 (필수, 최소 1개+)
- raw/company-tech-blogs/curity-bff-pattern-spa — Curity BFF pattern article (메인 근거)
- raw/official-docs/oauth-v2-1-draft-ietf — OAuth 2.1 draft (browser app이 client credentials를 사용하려는 경우의 BFF 조건부 권고)
- raw/official-docs/spring-security-resource-server-jwt — Spring Security (SPA Direct 측 비교 reference)
TODO
각 항목 옆에 증거 등급 표기: actually-implemented | locally-verified | prod-verified | documented-only | planned | needs-confirmation
- BFF 아키텍처 다이어그램 — 등급:
planned┌─────────────────┐ │ Keycloak │ └────────▲────────┘ │ OIDC (server-side) │ access/refresh │ token 보유 ┌────────┴────────┐ Browser (SPA) ── httpOnly session ────► │ BFF (Backend) │ ── Bearer token ──► Resource API cookie (JSESSIONID 등) │ - session store│ (BFF가 token │ - token cache │ holder) └─────────────────┘- 브라우저: 토큰 0개, session cookie만
- BFF: OAuth client 역할 + session ↔ token mapping 보관 (in-memory / Redis)
- Spring Security
oauth2Login구현 옵션 — 등급:documented-only- 의존성:
spring-boot-starter-oauth2-client application.yml:spring: security: oauth2: client: registration: keycloak: client-id: bff-client client-secret: <secret> authorization-grant-type: authorization_code redirect-uri: "{baseUrl}/login/oauth2/code/keycloak" scope: openid, profile, email provider: keycloak: issuer-uri: https://<keycloak>/realms/<realm>http.oauth2Login(...)+http.sessionManagement(...)(stateful session)- 백엔드가 자동으로 authorization code flow 수행 + session 생성 +
OAuth2AuthorizedClient에 토큰 보관
- 의존성:
- Spring Authorization Server 대안 — 등급:
documented-only- Spring Authorization Server는 AS 자체를 직접 구축하는 프로젝트 (Keycloak 대체). BFF와 직교한 결정.
- BFF 본질은 "백엔드가 OAuth client" — Keycloak을 AS로 두고 Spring
oauth2Login만으로 충분. - 본 P2A 학습 범위 외 (Keycloak 대체 안 함)
- BFF 단점 — 등급:
documented-only- Stateful: session store 필요 → scale-out 시 sticky session 또는 Redis 등 외부 session store
- 모바일 클라이언트: BFF는 web SPA 전용. 모바일은 별도 OAuth client 흐름 필요 → BFF가 모바일까지 커버하려면 추가 endpoint 설계
- CSRF surface 증가: session cookie 자동 첨부 → CSRF token 또는 SameSite 필요
- 운영 복잡도: session store 장애 시 전체 로그인 무효화
- 결정 기준 매트릭스 — 등급:
documented-only기준 SPA Direct (P2A) 우위 BFF 우위 XSS 민감도 (금융/의료) — ✅ 모바일/네이티브 동일 흐름 ✅ — 백엔드 stateless 유지 ✅ — 운영 단순성 (session store 불필요) ✅ — 토큰 revocation 즉시성 — ✅ (session 종료) OAuth 2.1 draft 권고 ✅ public client + PKCE ✅ client credentials가 필요한 browser app (D5) 다중 backend microservice ✅ (각자 JWT 검증) △ (BFF가 fan-out) - Curity / OAuth 2.1 draft 인용 — 등급:
documented-only- Curity: "The only way to protect tokens from being accessed by any malicious code is to keep them away from the browser."
- OAuth 2.1 draft §2.1: browser-based app 이 client credentials 를 사용하려는 경우 BFF 패턴을 권고 (
OA21-C4— "browser-based app 전반 의무" 아님, 조건부)
진행 중 메모
작업하며 떠오른 메모. 자유 형식.
- BFF는 "토큰을 백엔드에 두는 OAuth client" 패턴. P1A(Edge ForwardAuth)와 헷갈리기 쉬운데 두 가지가 다름:
- P1A는 reverse proxy가 인증 검문소(별도 컴포넌트 oauth2-proxy)
- BFF는 application backend 자체가 OAuth client + session holder
- Spring Security
oauth2Login은 본질적으로 BFF 패턴을 자동 구현해 줌. SPA Direct와 다른 starter(oauth2-clientvsoauth2-resource-server)를 쓴다는 점이 명확한 분기점.
결정 사항 (decisions)
추후 면접/회고에서 "왜 이렇게 했나" 답할 근거. 대안과 함께 기록.
- 2026-05-25: 본 keycloak-patterns 프로젝트는 SPA Direct (P2A)를 학습 목적의 1순위로 채택. BFF는 비교 문서로만 정리. 이유: canonical OIDC + PKCE 흐름을 먼저 이해하는 것이 목표.
- 2026-05-25: BFF 실 구현은 본 sub-sub-branch 범위 외 — SSOT §8 자신 없는 부분에 BFF 미경험으로 명시되어 있고, P3A 구현 이후 별도 확장 시 고려.
- 2026-05-25: BFF의 모바일 한계는 분명히 기록 (P2A 형제 branch에서 다중 클라이언트 장점을 활용한 결정과 연결).
결정-근거 매핑
각 결정이 어떤 raw source claim 으로 뒷받침되는지. company-tech-blog 인 Curity 는
company-case-study강도이며, OAuth 2.1 draft (official-standard) 와 Keycloak 공식 doc (official-vendor-doc) 으로만 official best practice 단언 가능. 단독 company-tech-blog 만으로는 official 단언 금지.
선택 조건열(R2): "이 조건일 때 이 결정, 다른 조건이면 어떤 대안". 본 branch 는 SPA Direct vs BFF 선택 자체가 주제이므로 각 결정의 선택 기준을 명시한다.
| Decision ID | Decision | 선택 조건 (언제 이 결정 / 언제 대안) | Supporting Claims | Evidence Strength | Open Risk |
|---|---|---|---|---|---|
| D1 | 본 keycloak-patterns 프로젝트는 SPA Direct (P2A) 를 학습 1순위로 채택, BFF 는 비교 문서로만 정리 | canonical OIDC + PKCE 흐름 학습이 1차 목표일 때 SPA Direct. XSS 민감 데이터(금융/의료) 운영 요구가 우선이면 BFF 를 1순위로 전환 | raw/official-docs/oauth-v2-1-draft-ietf.md#OA21-C1 (PKCE MUST — canonical SPA Direct 흐름), raw/official-docs/oauth-v2-1-draft-ietf.md#OA21-C4 (BFF 권고는 client credentials 사용 시) |
official-standard |
P2A SPA Direct 가 OAuth 2.1 §2.1 의 "client credentials 없는 public client + PKCE" 시나리오에 정합한지 본 프로젝트 client 설정 (Standard Flow + Public + PKCE S256) 으로 실 검증 필요 |
| D2 | BFF 실 구현은 본 sub-sub-branch 범위 외 (documented-only 유지) |
학습 우선순위/시간 제약 하에서는 문서화만. P3A 실 구현 완료 + XSS 민감 요구 발생 시 별도 확장 branch 로 실 구현 | UNSUPPORTED_DECISION (운영 결정 — 학습 우선순위 / 시간 제약 사유, 외부 자료가 직접 뒷받침하지 않음) | UNSUPPORTED_DECISION | 미구현 상태에서 면접/포트폴리오에 BFF 경험을 주장하면 거짓. 본 branch 의 모든 BFF 관련 등급은 documented-only 로 유지해야 함 |
| D3 | BFF 의 모바일 한계 (모바일은 별도 OAuth client 흐름 필요) 를 명시적으로 기록 | web SPA 단일 클라이언트면 BFF 성립. 모바일/native 클라이언트가 공존하면 native 는 별도 public-client PKCE 흐름(RFC 8252)이 MUST → BFF 단독으로 커버 불가, SPA Direct 가 다중 클라이언트에 유리 | raw/official-docs/security-oauth2-pkce-rfc-8252.md#RFC8252-C1 (native public client 는 자체 PKCE 흐름 MUST — "별도 흐름 필요" 절반을 corroborate) |
official-standard (부분 — "모바일은 별도 흐름 필요"만 근거; "BFF 가 모바일에서 동작 불가"는 여전히 추론) |
RFC8252-C1 은 native 가 자체 PKCE 흐름을 MUST 사용함을 보장할 뿐, "BFF session cookie 모델이 모바일에서 동작 안 한다"는 절대 표현은 직접 없음. 모바일 SDK 측 cookie 처리 / native browser handoff 는 별도 검증(Claims To Verify) 필요 |
| D4 | "토큰을 브라우저 밖에 두는 것이 XSS 로부터 보호하는 방법" 이라는 BFF motivation 인용 | XSS 위협 모델이 유의(브라우저에 token 존재 = 탈취 표면)한 SPA 일 때 이 motivation 이 BFF 채택 근거. XSS 표면이 무의미할 만큼 통제(CSP/sanitization)되면 SPA Direct 도 허용 | raw/company-tech-blogs/curity-bff-pattern-spa.md#CURITY-BFF-C1, raw/company-tech-blogs/curity-bff-pattern-spa.md#CURITY-BFF-C3, raw/company-tech-blogs/curity-bff-pattern-spa.md#CURITY-BFF-C4 |
company-case-study |
Curity 는 vendor 이며 본 인용은 official best practice 가 아님. "유일한 방법" 표현은 vendor 의 강한 주장 — OAuth 2.1 OA21-C4 로만 official 권고 corroborate 가능 |
| D5 | OAuth 2.1 draft 가 browser-based app 에서 BFF 패턴을 권고한다는 진술 | SPA 가 client credentials 를 사용하려는 경우(§2.1 조건)에 BFF 권고. public client + PKCE 만이면 SPA Direct 도 표준 허용 — "browser-based app 전반 의무" 아님 | raw/official-docs/oauth-v2-1-draft-ietf.md#OA21-C4 |
official-standard |
OA21-C4의 조건은 source-grounded이나, 본 프로젝트는 confidential BFF client와 client-secret runtime을 아직 구현하지 않았다. 실제 BFF 선택·동작 evidence는 documented-only다 |
구현 가이드
본 branch 는
documented-only비교/학습 branch — 실행 코드가 아니라 BFF 대안의 사전 명세 + 결정 기준 매트릭스의 근거 매핑이 산출물이다. 아래 in-scope 항목은 D1·D4·D5 결정의 도출이며, 소스가 원칙만 권고하고 detail 을 사용자가 정해야 하는 cell 은UNSUPPORTED_IMPL_DECISION라벨을 단다. 실 구현(코드) 등급은 모두planned.
1. 토큰 holder 명세
Trace: D4 (Curity BFF motivation —
CURITY-BFF-C1/C3/C4) + D5 (OAuth 2.1 조건부 권고 —OA21-C4). BFF 의 핵심은 토큰이 흐르는 경계와 holder 를 SPA Direct 대비 이동시키는 것.
- UNSUPPORTED_IMPL_DECISION: session store 백엔드(in-memory vs Redis)는 소스 미권고 — scale-out 요구에 따른 사용자 결정. trade-off: 학습 문서라 단일 인스턴스 in-memory 가정으로 충분, HA 필요 시 Redis 로 승격.
| 경계 | 무엇을 보유 | 메커니즘 | 근거 | 등급 |
|---|---|---|---|---|
| 브라우저 (SPA) | 토큰 0개, httpOnly session cookie(JSESSIONID 등)만 | BFF 가 발급한 session cookie 로 세션 식별 | CURITY-BFF-C4 (OAuth Agent 가 httpOnly session cookie 발급) |
documented-only |
| BFF (백엔드) | access/refresh token + session↔token mapping | server-side authorization code flow 수행 후 서버 메모리/store 에 보관 | CURITY-BFF-C3 (모든 통신이 backend OAuth Agent 경유, token 은 SPA 미도달) |
documented-only |
| BFF ↔ Keycloak | — (server-to-server) | server-side authorization_code flow, access/refresh 서버 보유 |
OA21-C4 (client credentials 시 BFF 권고) |
documented-only |
| BFF ↔ Resource API | BFF 가 보유 token 을 Bearer 로 fan-out | OAuth2AuthorizedClient 의 access token 을 downstream 호출에 첨부 |
UNSUPPORTED_IMPL_DECISION — Curity "OAuth Agent" 의 Spring 대응이 OAuth2AuthorizedClient 인지 미확정(Claims To Verify #4). trade-off: Spring 표준 API 로 가정, vendor 1:1 대응은 미검증 |
planned |
2. Spring Security oauth2Login (BFF) 구성 사전 명세
Trace: D5 (
OA21-C4— BFF 권고) + D4 (CURITY-BFF-C4— session cookie 모델). BFF 를 Spring 으로 구현하면 SPA Direct 의oauth2-resource-server대신oauth2-clientstarter 를 쓴다는 것이 명확한 분기점(진행 중 메모).
- UNSUPPORTED_IMPL_DECISION:
client-id: bff-client·scope·redirect-uri의 구체 값은 소스가 아니라 배포 환경이 정함. trade-off: 본 명세는 형태(shape)만 확정, 값은 실 realm 등록 시점에 채움.
| 항목 | 명세 | 근거 | 등급 |
|---|---|---|---|
| 의존성 | spring-boot-starter-oauth2-client (SPA Direct 의 -resource-server 와 대비되는 분기점) |
진행 중 메모 + D5 | documented-only |
| flow wiring | http.oauth2Login(...) + http.sessionManagement(...) — 백엔드가 authorization code flow 자동 수행 + session 생성 + OAuth2AuthorizedClient 에 토큰 보관 |
D5 (OA21-C4) |
documented-only |
| 브라우저 세션 | oauth2Login 이 인증 후 httpOnly session cookie 발급 (Curity 의 OAuth Agent 역할과 동등) |
CURITY-BFF-C4 |
documented-only |
application.yml |
registration.keycloak (client-id/secret/authorization_code/redirect-uri) + provider.keycloak.issuer-uri — 값은 UNSUPPORTED_IMPL_DECISION |
D5 | planned |
| 실 동작 검증 | Boot 3.x 에서 /login/oauth2/code/keycloak callback 200 + session cookie 발급 확인 |
Claims To Verify #1 | planned |
3. SPA Direct vs BFF 결정 기준 매트릭스 — 셀별 근거 매핑
Trace: D1 (SPA Direct 채택) + D5 (조건부 BFF 권고). 본 매트릭스가 "언제 어느 패턴" 선택 조건의 근거. §TODO 의 매트릭스(원본 표) 각 셀을 supporting claim 또는
UNSUPPORTED_IMPL_DECISION으로 분해 — Claims To Verify #5(셀→claim 매핑planned)를 종결.
- UNSUPPORTED_IMPL_DECISION: "백엔드 stateless"·"운영 단순성"·"다중 microservice"·"revocation 즉시성" 셀은 본 branch Sources 에 직접 인용이 없는 아키텍처 분석 통찰이다. trade-off: 일반 원리(BFF=stateful session store / JWT=stateless revocation 난이도)로 성립하나 official 단정 불가 — 형제 branch 결정에 위임(§엣지·실패·의존).
| 매트릭스 셀 | 우위 | 뒷받침 근거 | 판정 |
|---|---|---|---|
| XSS 민감도 (금융/의료) | BFF | CURITY-BFF-C1 (token 브라우저 밖 = XSS 보호), CURITY-BFF-C2 (SPA 악성코드가 token read 가능), CURITY-BFF-C6 (refresh token 탈취 위험) |
company-case-study |
| 모바일/네이티브 동일 흐름 | SPA Direct | RFC8252-C1 (native 는 자체 public-client PKCE 흐름 — SPA Direct token 흐름 재사용 가능, BFF session cookie 는 부적합) |
official-standard (부분) |
| 백엔드 stateless 유지 | SPA Direct | UNSUPPORTED_IMPL_DECISION — BFF 는 session store 필요(stateful)라는 일반 원리. CURITY-BFF-C4 의 "session cookie 발급"이 stateful 함의를 뒷받침하나 직접 단정은 아님 |
분석 통찰 |
| 운영 단순성 (session store 불필요) | SPA Direct | UNSUPPORTED_IMPL_DECISION — 위와 동일(session store 유무) |
분석 통찰 |
| 토큰 revocation 즉시성 | BFF (session 종료) | UNSUPPORTED_IMPL_DECISION — JWT stateless = revocation 난이도는 형제 raw/branch-notes/feature-keycloak-refresh-token-rotation 소관. 본 branch 직접 인용 없음 |
위임 |
| OAuth 2.1 draft 권고 | BFF (조건부) | OA21-C4 (client credentials 사용 시 BFF 권고 — 무조건 아님) |
official-standard |
| 다중 backend microservice | SPA Direct (각자 JWT 검증) | UNSUPPORTED_IMPL_DECISION — 각 RS 의 aud 검증은 형제 raw/branch-notes/feature-keycloak-spring-rs-audience-validator 소관. 본 branch 직접 인용 없음 |
위임 |
엣지·실패·의존
R4(깊이 게이트) 캡처용. BFF 는 SPA Direct 대비 stateful 로 전환되므로 정상 경로 밖의 실패/엣지가 늘어난다. 본 branch 는
documented-only이나, 실 구현 시 부딪힐 실패 경로와 형제 계약 의존을 미리 열거한다.
-
실패·엣지 경로:
- session store 장애 → 전체 로그인 무효화: BFF 는 session↔token mapping 을 보유(§구현 가이드 §1)하므로 store 장애 시 모든 활성 세션 유실. 기대 동작: 외부 session store(Redis) HA 또는 sticky session. 근거:
CURITY-BFF-C4의 session cookie 모델(D4). - CSRF surface 증가: session cookie 는 브라우저가 자동 첨부 → CSRF 취약. 기대 동작: CSRF token(동기화 토큰) 또는
SameSite=Lax/Strictcookie 속성 필수.CURITY-BFF-C4는 "session cookie 발급"만 보장하고 CSRF 통제는 미언급 — 별도 명시 필요. - scale-out 시 session sharing: 다중 BFF 인스턴스면 session 공유(Redis) 필수. sticky session 은 인스턴스 장애 시 해당 세션 유실.
UNSUPPORTED_IMPL_DECISION(§구현 가이드 §3 "백엔드 stateless" 셀과 동일 원리). - 모바일 클라이언트 handoff: BFF session cookie 모델은 native 앱에 부적합. native 는
RFC8252-C1의 public-client PKCE 별도 흐름이 MUST(D3). BFF 로 모바일까지 커버하려면 추가 endpoint 설계 필요. - Keycloak 미가용: BFF 는 server-side authorization code flow 로 token 을 획득하므로 로그인 시점 Keycloak 장애 → 신규 로그인 차단(기존 세션은 BFF 보유 token 만료 전까지 유지). SPA Direct 와 달리 브라우저가 직접 Keycloak 을 치지 않음.
- session store 장애 → 전체 로그인 무효화: BFF 는 session↔token mapping 을 보유(§구현 가이드 §1)하므로 store 장애 시 모든 활성 세션 유실. 기대 동작: 외부 session store(Redis) HA 또는 sticky session. 근거:
-
다른 계약 의존:
- raw/branch-notes/feature-keycloak-internal-spa-direct-no-google (P2A parent) 의
D1(SPA Direct = 브라우저 token 보유 정의) — 본 비교의 SPA Direct 기준선. 그 정의가 바뀌면 본 매트릭스 전체가 영향. - raw/branch-notes/feature-keycloak-spa-token-storage-tradeoff D1 — pure SPA는 access/refresh 모두 memory-only이며 reload 시 재인증한다. HttpOnly refresh cookie는 TMB/BFF variant일 때만 평가하며, 본 매트릭스의 SPA Direct 기준선은 owner 결론을 consume한다.
- raw/branch-notes/feature-keycloak-refresh-token-rotation 의
D1(rotation 활성화 — reuse detection) +D2(access token revocation = 짧은 TTL 로 해결) — 매트릭스 "revocation 즉시성" 셀(§구현 가이드 §3,UNSUPPORTED_IMPL_DECISION위임)이 이 결정에 의존. 그 branch 가 rotation 정책을 바꾸면 SPA Direct 의 revocation 약점 평가가 달라짐. - raw/branch-notes/feature-keycloak-spring-rs-audience-validator 의
D1(iss+sig+exp+aud 4종 검증, aud 는 custom validator 필수) +D4(SPA client scope 에 Audience mapper 등록 필수) — 매트릭스 "다중 microservice" 셀(위임)이 각 RS 의 aud 검증에 의존. fan-out 시 각 downstream 이 자기 client 를 aud 로 검증해야 cross-client reuse 방지. - raw/branch-notes/feature-keycloak-edge-forwardauth-no-google (P1A) — BFF 와 개념 혼동 방지(진행 중 메모). P1A = 별도 reverse proxy 가 인증 검문소, BFF = application backend 자체가 OAuth client. 계약 의존은 아니나 경계 구분 유지 필요.
- raw/branch-notes/feature-keycloak-internal-spa-direct-no-google (P2A parent) 의
검증해야 할 주장
공식 문서 / 사례는 근거지만, 본 프로젝트의 실제 동작은 자동 보장되지 않는다. 구현 전후 검증 항목.
| Claim | Why uncertain | How to verify | Status |
|---|---|---|---|
Spring Security oauth2Login (spring-boot-starter-oauth2-client) 가 본 branch 본문 yml 설정 그대로 Keycloak 과 authorization code flow 를 성공시키는지 |
본 branch 의 yml 은 documented-only 단계 — 실 구현 없음. starter 버전 / Spring Boot 3.x compat 확인 안 됨 |
실제 Spring Boot 3.x project 에 의존성 추가 + application.yml 적용 후 /login/oauth2/code/keycloak callback 200 확인, session cookie 발급 확인 |
planned |
| Keycloak 의 client 설정 (Standard Flow + Public + PKCE S256) 이 P2A SPA Direct 와 정합한지 | 본 branch 는 BFF 비교만 다루고 P2A client 설정의 실 등록을 안 했음 | Keycloak realm export → client config JSON 에서 standardFlowEnabled=true, publicClient=true, attributes.pkce.code.challenge.method=S256 확인 |
needs-confirmation |
| BFF 가 모바일 클라이언트에서 실제로 동작 불가한지 (또는 별도 흐름이 정확히 필요한지) | 본 branch Sources 에 직접 인용 없음 — 본문 통찰만 | RFC 8252 (OAuth 2.0 for Native Apps) 정독 + raw/official-docs/security-oauth2-pkce-rfc-8252.md 와 cross-check, 모바일 SDK 에서 BFF session cookie 핸들링 동작 확인 |
needs-confirmation |
| Curity 의 "OAuth Agent" 명명이 다른 vendor (Auth0, IdentityServer, Spring Authorization Server) 의 BFF 구현에도 1:1 대응되는지 | CURITY-BFF-C3 의 "OAuth Agent" 는 vendor-specific 명명 |
각 vendor 의 BFF docs 정독 — Spring Security oauth2Login 의 OAuth2AuthorizedClient 가 동등 역할인지 확인 |
planned |
| 결정 기준 매트릭스 (XSS 민감도 / 모바일 / stateless / 운영 / revocation / OAuth 2.1 권고 / multi-microservice) 의 각 셀이 본 sources 중 어느 인용으로 직접 뒷받침되는지 | 본 branch 본문 매트릭스는 종합 판단 — 셀별 source mapping 부재 | 각 셀마다 supporting claim 명시 또는 UNSUPPORTED 표시로 분해 | planned |
마주친 문제
- 이슈 1: P1A(Edge ForwardAuth)와 BFF의 차이를 한 문장으로 설명하기 까다로움.
- 원인: 둘 다 "토큰을 브라우저에서 분리"하지만 분리 주체와 위치가 다름
- 시도: (문서 정리)
- 해결: P1A = 별도 reverse proxy가 인증 / BFF = application backend 자체가 OAuth client —
documented-only
묶음
- raw/company-tech-blogs/curity-bff-pattern-spa
- raw/official-docs/keycloak-securing-apps-overview-official
- raw/official-docs/oauth-v2-1-draft-ietf
- raw/official-docs/owasp-html5-storage-xss-spa
본 sub-sub-branch 는 leaf — 자식 자료 없음. Phase 3 P3A 실 구현 또는 외부 산출물 단계에서 errors / interview prep / lectures 가 누적되면 본 섹션에서 그룹화.
오류 기록 (이 sub-sub-branch 작업 중 발생)
- (없음 — 현재 documented-only 단계)
면접 준비 (이 작업에서 나올 수 있는 면접 질문)
- (없음 — Phase 3 실 구현 단계에 누적)
관련 일일 노트
완료 후 정리
머지/종료 시점에 채움.
/ingest가 이 섹션을 기준으로 wiki/projects/에 추출.
- PR 링크: (미구현 — 문서까지만)
- 리뷰 메모:
- 머지 결과 / 배포 환경: 없음 (P2A는
documented-only범위) - wiki 추출 대상: 현 단계 없음. 6 패턴 + BFF 매트릭스 완성 후
wiki/concepts/bff-vs-spa-direct.md합성 후보. - 추출하지 않을 항목: BFF 자체 구현 없음. SPA Direct도 P2A 구현 없음.
documented-only유지.