feat: 문서 구조 변경 및 tech-visual 스킬 추가

This commit is contained in:
DongHyeonka
2026-09-04 18:20:00 +09:00
parent 43901f0abf
commit 2efb7ee1f2
683 changed files with 61180 additions and 10479 deletions
@@ -0,0 +1,60 @@
---
id: 19b55c39-c583-4161-9775-df954280a568
kind: PROJECT_DECISION
slug: bff-owns-token-when-browser-must-not
title: BFF가 OAuth Token을 관리하는 조건
topic: 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는 여전히 고려해야 된다.
@@ -0,0 +1,72 @@
---
id: 8c1ebea7-204e-445c-9812-0421d9eb0e9c
kind: PROJECT_DECISION
slug: federation-is-not-an-application-pattern
title: 외부 IdP와의 연동이라도 별도의 인증 방식이 아니다.
topic: OAuth/OIDC 인증 경계
project: KeyCloak Patterns
status: 게시 중
version: 17
decisionStatus: ADOPTED
decidedOn: 2026-08-24
studio: "https://hyeonworks.com/studio/documents/8c1ebea7-204e-445c-9812-0421d9eb0e9c/edit"
public: "https://hyeonworks.com/projects/keycloak-patterns/decisions/federation-is-not-an-application-pattern"
---
# 외부 IdP와의 연동이라도 별도의 인증 방식이 아니다.
Google, Keycloak, 애플리케이션 인증 구조는 각각 역할이 다르다.
Google은 실제 사용자 인증을 수행하는 외부 IDP이고, Keycloak은 Google의 인증 결과를 받아 애플리케이션이 사용할 토큰을 발급한다.
애플리케이션은 Google을 직접 신뢰하는 것이 아니라 Keycloak이 발급한 토큰을 기준으로 사용자를 인증한다.
SPA, BFF와 같은 구조는 로그인한 사용자의 토큰이나 세션을 어디에 관리할 것인지를 정한다.
따라서 외부 IDP가 붙더라도 인증 구조가 바뀌는 것은 아니다.
## 근거
- **외부 IdP 연동과 Application 인증 구조의 경계**
이 결정을 규칙으로 편 기준이다.
- **SPA에서 토큰을 직접 관리하면서 드러난 Browser Credential 경계**
브로커가 발급한 code를 받는 애플리케이션 경계다.
- **OAuth Token과 Application Session을 구분하는 기준**
upstream IdP 상태와 애플리케이션 상태를 같은 이름으로 부르지 않는다.
## 결정문
외부 IdP 연동은 별도의 인증 구조가 아니다.
Google과 같은 외부 IDP는 사용자의 인증을 담당하고, Keycloak은 그 인증 결과를 받아 애플리케이션이 신뢰할 수 있는 토큰을 발급한다.
SPA, Mediator, BFF, OAuth2-proxy와 같은 4가지 구조는 이렇게 발급된 토큰이나 세션을 애플리케이션에서 어디까지 노출하고 관리할지를 구분한다.
## 판단 이유
사용자가 Keycloak 로그인 화면에서 Google 로그인을 선택하면 브라우저는 Google의 Authorization Endpoint로 이동한다.
Google에서 인증이 끝나면 그 결과는 Keycloak으로 돌아오고, Keycloak은 이 응답을 검증해 자신의 사용자 정보와 연결한다.
그러고 나서 애플리케이션 callback에는 Keycloak이 발급한 Authorization Code가 전달된다.
애플리케이션은 Google과 직접 토큰을 교환하지 않는다.
애플리케이션은 Keycloak이 발급한 Authorization Code를 Keycloak의 Token Endpoint에서 토큰으로 교환한다.
Resource Server가 검증하는 issuer도 Google이 아니라 Keycloak이고, 애플리케이션은 Google token을 받지 않는다.
그래서 Google 로그인을 추가해도 애플리케이션의 토큰 관리 구조는 달라지지 않는다.
SPA라면 여전히 브라우저에서 토큰을 관리하고, BFF라면 서버가 토큰을 관리하면서 API를 대신 호출해준다.
브라우저가 token을 받는지, 어느 계층이 API를 부르는지도 그대로다.
Google을 구조 하나로 세게 되면 upstream IdP 경계와 애플리케이션 OAuth 경계를 같은 기준으로 묶게 되는데, 두 경계는 검증 방법이 서로 다르다.
두 경계를 섞어 두면 비교표에 성격이 다른 항목이 끼어들고, 계정 연결 규칙도 인증 구조 이야기에 섞여서 따로 설계하지 않고 넘어가게 된다.
그래서 외부 IDP 연동과 애플리케이션 인증 구조는 별도의 경계로 나누어 설계하고 검증한다.
## 영향
- Google을 추가하더라도 애플리케이션이 신뢰하고 토큰을 검증하는 대상은 계속 Keycloak이다.
또한 토큰을 브라우저와 서버 중 어디에서 관리하고 어느 계층에서 API를 호출할지는 기존 4가지 구조가 정하는 그대로다.
- 외부 IDP의 계정을 기존 사용자와 어떻게 연결할지는 인증구조와 별개의 문제다.
외부 계정을 식별할 때는 Google과 같은 인증 제공자와 해당 제공자가 부여한 사용자 고유 식별자를 같이 사용한다.
이메일 주소는 변경될 수 있고 서로 다른 인증 제공자에서 같은 이메일을 사용할 수도 있기 때문에 이메일이 같다라는 이유로 기존 계정과 자동으로 연결하지 않는다.
- 외부 IDP 연동은 테스트 환경에서 확인할 부분과 실제 서비스 환경에서 확인할 부분을 나눠서 검증한다.
Mock Provider를 사용한 테스트에서는 KeyCloak이 외부 IDP의 인증 결과를 정상적으로 받아들이는지,
필요한 사용자 정보가 정상적으로 매핑되는지 확인한다.
실제 Google과 같은 외부 IDP를 연동할 때는 실제 계정으로 로그인이 가능한지, 공개 HTTPS Callback이 정상 작동 하는지, 사용자 동의 과정까지 진행되는지 확인해야 한다.
- Google과 같은 외부 IDP가 늘어나면 KeyCloak에서 관리해야 할 연동 설정도 많아진다.
이 연동 설정을 애플리케이션 팀이 관리할지 별도의 인프라 팀이 관리할지는 아직 정하지 않았다.
실무에서 어느 쪽이 맡는지도 확인하지 않았다.