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>
62 lines
3.8 KiB
Markdown
62 lines
3.8 KiB
Markdown
---
|
|
id: 19b55c39-c583-4161-9775-df954280a568
|
|
kind: PROJECT_DECISION
|
|
slug: bff-owns-token-when-browser-must-not
|
|
title: BFF가 OAuth Token을 관리하는 조건
|
|
topic: oauth-oidc-auth-boundary
|
|
topicName: OAuth/OIDC 인증 경계
|
|
project: KeyCloak Patterns
|
|
status: 게시 중
|
|
version: 23
|
|
decisionStatus: PROPOSED
|
|
decidedOn: 2026-08-31
|
|
studio: "https://hyeonworks.com/studio/documents/19b55c39-c583-4161-9775-df954280a568/edit"
|
|
public: "https://hyeonworks.com/projects/keycloak-patterns/decisions/bff-owns-token-when-browser-must-not"
|
|
---
|
|
|
|
# BFF가 OAuth Token을 관리하는 조건
|
|
|
|
애플리케이션 계층에서 API 응답 조합과 인가를 처리하면서도 브라우저 JavaScript에는 OAuth Token을 노출하지 않아야 한다면 BFF 구조를 선택할 수 있다.
|
|
|
|
이 경우 BFF가 Authorization Code를 Token으로 교환하고, Access Token과 Refresh Token을 서버에 보관한다.
|
|
브라우저는 OAuth Token 대신 Application Session을 이용해 BFF를 호출하고,
|
|
BFF는 저장된 Access Token으로 Downstream Resource Server를 호출한다.
|
|
|
|
## 근거
|
|
|
|
- **Browser Token을 없애면서 BFF에 Session과 CSRF 책임이 생긴 과정**
|
|
이 결정이 가리키는 구조를 실제로 실행해 본 기록이다.
|
|
- **BFF 인증 구조 설계 기준**
|
|
이 결정이 PROPOSED인 동안의 실제 적용 기준이다.
|
|
- **OAuth/OIDC 인증 패턴 선택 기준**
|
|
이 결정을 적용할 조건과 피해야 할 조건이 여기 있다.
|
|
- **Refresh Token 관리만 서버로 이전, Access Token은 여전히 Browser에 노출**
|
|
access token이 브라우저로 나가 이 요구를 만족하지 못한 경우다.
|
|
|
|
## 결정문
|
|
|
|
브라우저에 OAuth token을 노출하지 않으면서 애플리케이션이 Resource Server 호출을 중계하고 조합해야 하는 경우, BFF가 authorization code 교환과 token 보관, downstream API 호출을 소유한다.
|
|
|
|
브라우저에는 애플리케이션 session만 제공한다.
|
|
|
|
## 판단 이유
|
|
|
|
브라우저에 OAuth token을 전달하지 않으려면 server가 authorization code를 교환하고 access token을 사용해 downstream API를 호출해야 한다.
|
|
|
|
Mediator 구조에서는 브라우저가 Resource Server를 직접 호출하므로 access token을 /token/access 응답으로 전달한다.
|
|
그래서 브라우저에 OAuth token을 제공하지 않는다는 요구에는 맞지 않는다.
|
|
|
|
Forward-Auth 구조도 브라우저에 OAuth token을 전달하지 않을 수 있지만 upstream은 JWT를 직접 검증하지 않고 edge가 제공한 identity header를 사용한다.
|
|
애플리케이션이 access token으로 여러 Resource Server를 직접 호출하거나 사용자별 API 조합을 처리해야 한다면 BFF 쪽이 요구에 더 잘 맞는다.
|
|
|
|
그래서 이 결정을 적용할지는 브라우저에 OAuth token을 전달하지 않아야 하는지와 함께, 애플리케이션이 downstream API 호출과 조합을 직접 맡아야 하는지까지 보고 정한다.
|
|
|
|
## 영향
|
|
|
|
- BFF가 로그인 상태와 access token, refresh token을 보관하는 보안 구성요소가 된다. 요청을 그대로 넘기는 proxy와 같은 것으로 다루지 않는다.
|
|
- 상태 변경 요청마다 CSRF 검증이 필요해진다. 노출되는 값과 제출해야 하는 값이 다를 수 있어서 클라이언트 코드도 그 차이를 알고 있어야 한다.
|
|
- 재시작과 replica 이동을 견딜 공유 저장소와 저장 token 암호화, 암호화 key 교체를 설계해야 하는데 아직 정하지 않은 문제로 남아 있다.
|
|
- logout이 애플리케이션 session과 authorized client를 함께 지워야 하는데, 관리가 달라서 한 번의 삭제로 두 상태가 함께 지워지지 않는다.
|
|
- 모든 UI 요청이 BFF를 지나게 되어서 지연과 단일 장애 지점을 준비해야 한다.
|
|
- 브라우저에서 token을 없애도 XSS는 여전히 고려해야 된다.
|