Files
document-haness/docs/keycloak/tech-log-studio/oauth-oidc-auth-boundary/reference/reference-pattern-selection.md
T
DongHyeonkaandClaude Fable 5.1 4d50bb939a docs(keycloak): adopt the decomposition contract, fix the redirect URI, strip evaluative prose
- 계약 채택 — 독자 질문, 후보 29건(PROMOTE 24 · MERGE_INTO 4 · KEEP_IN_SSOT 1). 게시 중
  17건은 전부 유지. 저장소 keycloak-pattern 은 패턴 넷이 브랜치로 갈라져 있어 revisions 로
  tip 넷을 적었다. keycloak-session-store 는 같은 저장소 @ cdac9b8
- 게시된 기록의 redirect_uri 가 SSOT·코드와 달랐다 — OAuth2callback.html → callback.html
  (frontend/src/app.js 에서 확인). 계약 title 이 기록과 다른 7건도 기록 쪽으로 맞췄다
- 미작성 1건 작성 — 패턴 검증을 실제로 돌릴 때의 안전한 순서(Reference)
- 리뷰 100건 반영 — 설명 뒤에 붙은 평가·차례 예고·독자 오해 가정·작성 지시를 지웠다.
  삭제가 남긴 조각 4건을 고치고, 원래부터 잘려 있던 로컬 미리보기 라벨 1건도 닫았다

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 12:39:20 +09:00

8.5 KiB

id, kind, slug, title, topic, topicName, project, status, version, verifiedOn, studio, public, sourceRevision, source
id kind slug title topic topicName project status version verifiedOn studio public sourceRevision source
3f886154-1b85-407b-bda4-57d28370e745 REFERENCE oauth-oidc-pattern-selection-criteria OAuth/OIDC 인증 패턴 선택 기준 oauth-oidc-auth-boundary OAuth/OIDC 인증 경계 KeyCloak Patterns 게시 중 23 2026-08-30 https://hyeonworks.com/studio/documents/3f886154-1b85-407b-bda4-57d28370e745/edit https://hyeonworks.com/references/oauth-oidc-pattern-selection-criteria keycloak-patterns-lab@2026-08
final/document.md#검토한-선택지와-막힌-지점-책임과-데이터
final/document.md#얻은-것-잃은-것-적용하지-않을-때-사다리가-아니라
final/document.md#얻은-것-잃은-것-적용하지-않을-때-변경-경로

OAuth/OIDC 인증 패턴 선택 기준

SPA(Single Page Application), Mediator, BFF(Backend for Frontend), Forward-Auth는 토큰과 인증 상태를 다루는 방식이 서로 다르다. 브라우저가 액세스 토큰을 직접 쓰는지, Resource Server를 누가 호출하는지, 서버가 어떤 인증 상태를 보관하는지, Resource Server가 어떤 자격 증명을 검증하는지, CSRF(Cross-Site Request Forgery)를 어느 계층에서 처리하는지를 나란히 놓고 비교할 수 있다. 애플리케이션의 요구사항과 배포·운영 환경에 맞춰 고른다.

관계

  • SPA에서 토큰을 직접 관리하면서 드러난 Browser Credential 경계 브라우저가 인가 코드를 토큰으로 바꾸고, 그 토큰을 들고 있다가, API까지 직접 호출한다.
  • Refresh Token 관리만 서버로 이전, Access Token은 여전히 Browser에 노출 Mediator가 리프레시 토큰을 서버에 두는데, 브라우저는 넘겨받은 액세스 토큰으로 Resource Server를 직접 호출한다.
  • Browser Token을 없애면서 BFF에 Session과 CSRF 책임이 생긴 과정 BFF가 인가 코드 교환과 토큰 보관, Resource Server 호출을 모두 처리하고 브라우저는 세션 쿠키만 받는다.
  • Forward-Auth에서 Client가 보낸 Identity Header를 신뢰하면 안 되는 이유 인증을 엣지로 옮기면 보호 자원이 검증하는 대상이 JWT에서 헤더로 바뀐다.

목적

브라우저에 OAuth 토큰이 노출되는 정도만 놓고 보면 구조마다 차이가 난다. 다만 토큰을 다른 계층으로 옮기면 브라우저에 노출되는 범위가 달라지는데, 그 토큰을 맡은 계층에서는 처리해야 할 항목이 늘어난다.

예를 들어 BFF는 OAuth 토큰을 서버에 보관해 브라우저에서 토큰 원문을 없앨 수 있다. 하지만 그러려면 서버가 세션과 Authorized Client를 관리해야 한다. Authorized Client는 서버가 액세스 토큰과 리프레시 토큰을 보관하는 곳이다. 그래서 세션 보호와 CSRF 방어, 공유 저장소 같은 설계가 새로 필요해진다.

Forward-Auth 구조에서는 애플리케이션이 OAuth 토큰을 직접 관리하는 책임을 더 줄일 수 있다. 대신 애플리케이션이 엣지에서 넘어온 사용자 정보 헤더를 신뢰하게 되므로, 헤더 위조 방지와 직접 접근 차단, 신뢰할 수 있는 네트워크 경계를 구성해야 한다.

어느 구조가 더 안전한지를 먼저 정하지 않고, 요구사항마다 무엇을 확인해야 하는지를 본다.

규칙

1. 다섯 항목으로 구조를 비교한다

브라우저가 액세스 토큰을 쓰는지, Resource Server를 누가 호출하는지, 서버가 어떤 인증 상태를 관리하는지, Resource Server가 어떤 자격 증명을 검증하는지, CSRF를 어디에서 처리하는지를 확인한다.

이 다섯 항목은 패턴 이름 대신 요청 하나를 끝까지 따라가서 채운다. 실제 엔드포인트와 메서드, 중간에 생기는 데이터, 성공 응답과 실패 응답까지 봐야 한다. 같은 질문을 로그인할 때와 로그인 뒤 API를 부를 때 각각 던진다.

SPA와 Mediator에서는 브라우저가 액세스 토큰으로 Resource Server를 직접 호출한다. SPA는 Bearer 액세스 토큰을 Authorization 헤더에 직접 넣고 인증에는 쿠키를 쓰지 않는다. Mediator는 로그인 세션과 OAuth 토큰을 서버에서도 관리하고, 로그인이 끝나면 브라우저에 액세스 토큰을 전달한다.

BFF에서는 브라우저가 세션 쿠키로 BFF를 호출하고, BFF가 서버에 저장한 액세스 토큰으로 Resource Server를 호출한다. 그래서 브라우저에는 OAuth 토큰을 전달하지 않지만 세션과 Authorized Client를 서버에서 관리해야 한다.

Forward-Auth에서는 인증 프록시가 세션을 관리하고, 인증이 끝난 요청에 사용자 정보를 붙여 애플리케이션으로 넘긴다. 애플리케이션이 이 정보를 인증 근거로 쓴다면 엣지가 붙인 헤더를 믿을 수 있도록 직접 접근 차단과 헤더 덮어쓰기, 내부 자격 증명 검증 같은 보호를 따로 둬야 한다.

2. 피해야 할 조건을 먼저 확인한다

정책상 OAuth 토큰을 브라우저에 둘 수 없다면, 토큰을 Local Storage 대신 JavaScript 메모리에만 보관해도 요구사항을 채우지 못한다. 저장 위치만 달라졌을 뿐 브라우저 JavaScript가 여전히 토큰을 직접 다루기 때문이다. 이때는 브라우저가 액세스 토큰을 받는 SPA와 현재의 Mediator 구조를 선택 대상에서 뺀다.

마찬가지로 애플리케이션으로 바로 들어오는 경로를 막을 수 없거나, 밖에서 들어온 사용자 정보 헤더를 엣지에서 확실히 지우거나 덮어쓸 수 없다면, 엣지가 전달한 사용자 정보를 인증 근거로 쓰는 구조는 고르지 않는다.

3. 선택 조건과 운영 책임을 같이 문서화한다

어떤 인증 구조를 골랐는지만 적지 않는다. 어떤 보안 요구사항과 운영 조건 때문에 그 구조를 골랐는지 함께 적는다.

그 구조를 적용하기 어려운 조건도 같이 적는다. 브라우저에 OAuth 토큰을 둘 수 없는 환경에서는 SPA를 고르기 어렵다. 애플리케이션으로 바로 들어오는 경로나 사용자 정보 헤더를 안전하게 통제할 수 없는 환경에서는 Forward-Auth를 적용하기 어렵다.

4. 이름으로 운영 속성을 추정하지 않는다

실제 운영에 적용할 때는 서버가 재시작되거나 특정 인스턴스에 장애가 나도 로그인 상태를 유지할 수 있는지, 여러 레플리카가 필요한 세션과 토큰 정보를 공유할 수 있는지, 저장소 장애가 났을 때 어떻게 복구할지를 따로 확인해야 한다.

내부 자격 증명이나 암호화 키와 같은 비밀값을 안전하게 보관하고 교체할 수 있는지도 함께 검증한다. 구조를 고를 때 이런 운영 항목까지 같이 적는다.

5. 자격 증명의 위치가 바뀌면 저장·전달·검증 주체도 바뀐다

패턴을 바꿀 때는 기존 책임이 어느 계층으로 옮겨 가는지까지 확인해야 한다.

예를 들어 Forward-Auth 구조에서는 엣지가 인증된 사용자 정보를 헤더로 애플리케이션에 전달할 수 있다. 처음에는 사용자 이름이나 이메일처럼 인증에 필요한 정보만 전달하더라도, 애플리케이션의 요구사항이 늘면서 역할이나 권한, 도메인에 묶인 사용자 정보까지 헤더에 계속 붙을 수 있다.

엣지가 전달해야 하는 정보가 이렇게 늘어나고, 인가 판단이나 화면에 필요한 여러 API 응답의 조합까지 애플리케이션에 필요해진다면, 그 책임을 엣지에 계속 얹기보다 BFF에서 인가와 API 호출을 처리하는 구조가 더 맞는지 다시 검토한다.

적용 조건

  • 인증 구조를 처음 고를 때
  • 한 구조에서 다른 구조로 옮기려 할 때
  • 구조를 문서로 비교할 때

예외

  • 브라우저에 토큰을 둘 수 없고 서버가 API를 조합해야 하면 남는 선택지는 하나다.
  • 학습이나 시연이 목적이면 운영 속성까지 비교하지 않아도 된다.

예시

  • SPA: 브라우저가 인가 코드 교환과 토큰 보관, API 호출을 모두 맡는다.
  • Mediator: 리프레시 토큰은 서버에 두고, 액세스 토큰은 응답 본문으로 브라우저에 돌려준다.
  • BFF: 서버가 인가 코드 교환과 토큰 관리, API 호출을 맡고 브라우저는 세션 쿠키로 BFF를 호출한다.
  • Forward-Auth: 엣지가 인증하고 애플리케이션은 엣지가 붙인 헤더를 본다.