- generic [ref=f15e3]: - link "본문으로 건너뛰기" [ref=f15e4] [cursor=pointer]: - /url: "#main-content" - banner [ref=f15e5]: - generic [ref=f15e6]: - link "TechLog Studio" [ref=f15e7] [cursor=pointer]: - /url: /studio - text: TechLog - generic [ref=f15e8]: Studio - navigation "Studio 주 탐색" [ref=f15e10]: - link "작업본" [ref=f15e11] [cursor=pointer]: - /url: /studio/documents - link "게시 기록" [ref=f15e12] [cursor=pointer]: - /url: /studio/publications - link "새 문서" [ref=f15e13] [cursor=pointer]: - /url: /studio/documents/new - link "주제·프로젝트" [ref=f15e14] [cursor=pointer]: - /url: /studio/taxonomy - link "릴리즈" [ref=f15e15] [cursor=pointer]: - /url: /studio/releases - link "공개 사이트 보기" [ref=f15e16] [cursor=pointer]: - /url: / - button "로그아웃" [ref=f15e17] - main [ref=f15e18]: - generic [ref=f15e19]: - generic [ref=f15e20]: - region [ref=f15e21]: - generic [ref=f15e22]: - paragraph [ref=f15e23]: REFERENCE · VERSION 11 - heading "문서 편집" [level=1] [ref=f15e24] - paragraph [ref=f15e25]: OAuth/OIDC 인증 패턴 선택 기준 - region [ref=f15e26]: - generic [ref=f15e27]: - paragraph [ref=f15e28]: DOCUMENT - heading "기본 정보" [level=2] [ref=f15e29] - generic [ref=f15e30]: - generic [ref=f15e31]: - generic [ref=f15e32]: 제목 - textbox "제목" [ref=f15e33]: OAuth/OIDC 인증 패턴 선택 기준 - generic [ref=f15e34]: - generic [ref=f15e35]: slug - textbox "slug" [ref=f15e36]: - /placeholder: 비우면 제목에서 만듭니다 (영문 소문자·숫자·하이픈) - text: oauth-oidc-pattern-selection-criteria - generic [ref=f15e37]: - generic [ref=f15e38]: 요약 - textbox "요약" [ref=f15e39]: SPA, Mediator, BFF, OAuth2-Proxy는 브라우저의 access token 사용 여부, Resource Server 호출 주체, server-side 인증 상태, 보호 자원이 검증하는 credential, CSRF 처리 위치가 서로 다르다. 패턴 선택에서는 이 다섯 항목을 요구사항과 운영 환경에 맞춰 비교한다. - generic [ref=f15e40]: - generic [ref=f15e41]: Topic - combobox "Topic" [ref=f15e42]: - option "선택하지 않음" - option "OAuth/OIDC 인증 경계" [selected] - generic [ref=f15e43]: - generic [ref=f15e44]: Project - combobox "Project" [ref=f15e45]: - option "미지정" - option "Backend Clean Architecture" - option "KeyCloak Patterns" [selected] - option "Liner N + 1문제" - group "관계" [ref=f15e46]: - generic [ref=f15e48]: - generic [ref=f15e49]: - generic [ref=f15e50]: 관계 1 대상 - combobox "관계 1 대상" [ref=f15e51]: - option "대상 선택" - option "인증 구조를 보안 성숙도 단계로 취급하지 않는다" [disabled] - option "서버 세션 기반 인증 구조는 다중 인스턴스에서 어떻게 운영할 것인가" - option "Authorization Code Flow의 Endpoint와 Credential 이동 기준" - option "BFF 인증 구조 설계 기준" - option "BFF가 OAuth Token을 관리하는 조건" - option "BFF의 Session과 OAuth2AuthorizedClient를 어디에 저장할 것인가" - option "Browser Token을 없애면서 BFF에 Session과 CSRF 책임이 생긴 과정" [disabled] - option "Forward-Auth 구조에서 Application Authorization을 어디까지 Edge에 둘 것인가" - option "Forward-Auth에서 Client가 보낸 Identity Header를 신뢰하면 안 되는 이유" [disabled] - option "Forward-Auth에서 Identity Header를 신뢰하기 위한 조건" - option "외부 IdP Federation을 별도의 인증 구조로 세지 않는다" - option "외부 IdP Federation과 Application 인증 경계" - option "OAuth/OIDC 인증 패턴 선택 기준" - option "OAuth Token과 Application Session을 구분하는 기준" - option "Public Client와 Confidential Client 구분 기준" - option "Refresh Token 관리만 서버로 이전, Access Token은 여전히 Browser에 노출" [disabled] - option "Refresh Token Rotation과 다중 Replica 경쟁을 어떻게 처리할 것인가" - option "SPA에서 토큰을 직접 관리하면서 드러난 Browser Credential 경계" [selected] - generic [ref=f15e52]: - generic [ref=f15e53]: 관계 1 이유 - textbox "관계 1 이유" [ref=f15e54]: 브라우저가 code 교환과 token 보관, API 호출을 모두 맡는다. - generic [ref=f15e55]: - button "위로" [disabled] [ref=f15e56] - button "아래로" [ref=f15e57] - button "삭제" [ref=f15e58] - generic [ref=f15e59]: - generic [ref=f15e60]: - generic [ref=f15e61]: 관계 2 대상 - combobox "관계 2 대상" [ref=f15e62]: - option "대상 선택" - option "인증 구조를 보안 성숙도 단계로 취급하지 않는다" [disabled] - option "서버 세션 기반 인증 구조는 다중 인스턴스에서 어떻게 운영할 것인가" - option "Authorization Code Flow의 Endpoint와 Credential 이동 기준" - option "BFF 인증 구조 설계 기준" - option "BFF가 OAuth Token을 관리하는 조건" - option "BFF의 Session과 OAuth2AuthorizedClient를 어디에 저장할 것인가" - option "Browser Token을 없애면서 BFF에 Session과 CSRF 책임이 생긴 과정" [disabled] - option "Forward-Auth 구조에서 Application Authorization을 어디까지 Edge에 둘 것인가" - option "Forward-Auth에서 Client가 보낸 Identity Header를 신뢰하면 안 되는 이유" [disabled] - option "Forward-Auth에서 Identity Header를 신뢰하기 위한 조건" - option "외부 IdP Federation을 별도의 인증 구조로 세지 않는다" - option "외부 IdP Federation과 Application 인증 경계" - option "OAuth/OIDC 인증 패턴 선택 기준" - option "OAuth Token과 Application Session을 구분하는 기준" - option "Public Client와 Confidential Client 구분 기준" - option "Refresh Token 관리만 서버로 이전, Access Token은 여전히 Browser에 노출" [selected] - option "Refresh Token Rotation과 다중 Replica 경쟁을 어떻게 처리할 것인가" - option "SPA에서 토큰을 직접 관리하면서 드러난 Browser Credential 경계" [disabled] - generic [ref=f15e63]: - generic [ref=f15e64]: 관계 2 이유 - textbox "관계 2 이유" [ref=f15e65]: mediator가 refresh token을 관리하고 브라우저가 access token으로 API를 직접 호출하는 구성을 확인했다. - generic [ref=f15e66]: - button "위로" [ref=f15e67] - button "아래로" [ref=f15e68] - button "삭제" [ref=f15e69] - generic [ref=f15e70]: - generic [ref=f15e71]: - generic [ref=f15e72]: 관계 3 대상 - combobox "관계 3 대상" [ref=f15e73]: - option "대상 선택" - option "인증 구조를 보안 성숙도 단계로 취급하지 않는다" [disabled] - option "서버 세션 기반 인증 구조는 다중 인스턴스에서 어떻게 운영할 것인가" - option "Authorization Code Flow의 Endpoint와 Credential 이동 기준" - option "BFF 인증 구조 설계 기준" - option "BFF가 OAuth Token을 관리하는 조건" - option "BFF의 Session과 OAuth2AuthorizedClient를 어디에 저장할 것인가" - option "Browser Token을 없애면서 BFF에 Session과 CSRF 책임이 생긴 과정" [selected] - option "Forward-Auth 구조에서 Application Authorization을 어디까지 Edge에 둘 것인가" - option "Forward-Auth에서 Client가 보낸 Identity Header를 신뢰하면 안 되는 이유" [disabled] - option "Forward-Auth에서 Identity Header를 신뢰하기 위한 조건" - option "외부 IdP Federation을 별도의 인증 구조로 세지 않는다" - option "외부 IdP Federation과 Application 인증 경계" - option "OAuth/OIDC 인증 패턴 선택 기준" - option "OAuth Token과 Application Session을 구분하는 기준" - option "Public Client와 Confidential Client 구분 기준" - option "Refresh Token 관리만 서버로 이전, Access Token은 여전히 Browser에 노출" [disabled] - option "Refresh Token Rotation과 다중 Replica 경쟁을 어떻게 처리할 것인가" - option "SPA에서 토큰을 직접 관리하면서 드러난 Browser Credential 경계" [disabled] - generic [ref=f15e74]: - generic [ref=f15e75]: 관계 3 이유 - textbox "관계 3 이유" [ref=f15e76]: BFF가 code 교환, token 보관, Resource Server 호출을 모두 처리하는 구성을 확인했다. - generic [ref=f15e77]: - button "위로" [ref=f15e78] - button "아래로" [ref=f15e79] - button "삭제" [ref=f15e80] - generic [ref=f15e81]: - generic [ref=f15e82]: - generic [ref=f15e83]: 관계 4 대상 - combobox "관계 4 대상" [ref=f15e84]: - option "대상 선택" - option "인증 구조를 보안 성숙도 단계로 취급하지 않는다" [disabled] - option "서버 세션 기반 인증 구조는 다중 인스턴스에서 어떻게 운영할 것인가" - option "Authorization Code Flow의 Endpoint와 Credential 이동 기준" - option "BFF 인증 구조 설계 기준" - option "BFF가 OAuth Token을 관리하는 조건" - option "BFF의 Session과 OAuth2AuthorizedClient를 어디에 저장할 것인가" - option "Browser Token을 없애면서 BFF에 Session과 CSRF 책임이 생긴 과정" [disabled] - option "Forward-Auth 구조에서 Application Authorization을 어디까지 Edge에 둘 것인가" - option "Forward-Auth에서 Client가 보낸 Identity Header를 신뢰하면 안 되는 이유" [selected] - option "Forward-Auth에서 Identity Header를 신뢰하기 위한 조건" - option "외부 IdP Federation을 별도의 인증 구조로 세지 않는다" - option "외부 IdP Federation과 Application 인증 경계" - option "OAuth/OIDC 인증 패턴 선택 기준" - option "OAuth Token과 Application Session을 구분하는 기준" - option "Public Client와 Confidential Client 구분 기준" - option "Refresh Token 관리만 서버로 이전, Access Token은 여전히 Browser에 노출" [disabled] - option "Refresh Token Rotation과 다중 Replica 경쟁을 어떻게 처리할 것인가" - option "SPA에서 토큰을 직접 관리하면서 드러난 Browser Credential 경계" [disabled] - generic [ref=f15e85]: - generic [ref=f15e86]: 관계 4 이유 - textbox "관계 4 이유" [ref=f15e87]: 인증이 edge로 가면 보호 자원이 검증하는 것이 JWT에서 헤더로 바뀐다. - generic [ref=f15e88]: - button "위로" [ref=f15e89] - button "아래로" [ref=f15e90] - button "삭제" [ref=f15e91] - generic [ref=f15e92]: - generic [ref=f15e93]: - generic [ref=f15e94]: 관계 5 대상 - combobox "관계 5 대상" [ref=f15e95]: - option "대상 선택" - option "인증 구조를 보안 성숙도 단계로 취급하지 않는다" [selected] - option "서버 세션 기반 인증 구조는 다중 인스턴스에서 어떻게 운영할 것인가" - option "Authorization Code Flow의 Endpoint와 Credential 이동 기준" - option "BFF 인증 구조 설계 기준" - option "BFF가 OAuth Token을 관리하는 조건" - option "BFF의 Session과 OAuth2AuthorizedClient를 어디에 저장할 것인가" - option "Browser Token을 없애면서 BFF에 Session과 CSRF 책임이 생긴 과정" [disabled] - option "Forward-Auth 구조에서 Application Authorization을 어디까지 Edge에 둘 것인가" - option "Forward-Auth에서 Client가 보낸 Identity Header를 신뢰하면 안 되는 이유" [disabled] - option "Forward-Auth에서 Identity Header를 신뢰하기 위한 조건" - option "외부 IdP Federation을 별도의 인증 구조로 세지 않는다" - option "외부 IdP Federation과 Application 인증 경계" - option "OAuth/OIDC 인증 패턴 선택 기준" - option "OAuth Token과 Application Session을 구분하는 기준" - option "Public Client와 Confidential Client 구분 기준" - option "Refresh Token 관리만 서버로 이전, Access Token은 여전히 Browser에 노출" [disabled] - option "Refresh Token Rotation과 다중 Replica 경쟁을 어떻게 처리할 것인가" - option "SPA에서 토큰을 직접 관리하면서 드러난 Browser Credential 경계" [disabled] - generic [ref=f15e96]: - generic [ref=f15e97]: 관계 5 이유 - textbox "관계 5 이유" [ref=f15e98]: 이 기준의 첫 항목을 프로젝트 결정으로 굳힌 기록이다. - generic [ref=f15e99]: - button "위로" [ref=f15e100] - button "아래로" [disabled] [ref=f15e101] - button "삭제" [ref=f15e102] - button "관계 추가" [ref=f15e103] - region [ref=f15e104]: - generic [ref=f15e105]: - paragraph [ref=f15e106]: REFERENCE - heading "재사용할 기준" [level=2] [ref=f15e107] - generic [ref=f15e108]: - generic [ref=f15e109]: 목적 - textbox "목적" [ref=f15e110]: 브라우저에 token이 덜 보이는 순서는 있다. 그 순서를 보안 등급으로 쓰면 판단이 틀린다. BFF는 브라우저 token을 없애지만 server session과 공유 저장소를 만든다. Forward-Auth는 애플리케이션의 token custody를 줄이지만 edge 헤더 신뢰와 network 경계를 만든다. 새로 생긴 쪽을 감당할 수 없는 환경이면 앞 구조가 더 안전하다. 번호가 아니라 배치를 본다. - group "규칙" [ref=f15e111]: - generic [ref=f15e113]: - generic [ref=f15e114]: - generic [ref=f15e115]: 규칙 1 제목 - textbox "규칙 1 제목" [ref=f15e116]: 다섯 항목으로 구조를 비교한다 - generic [ref=f15e117]: - generic [ref=f15e118]: 규칙 1 본문 - textbox "규칙 1 본문" [ref=f15e119]: "구조를 비교할 때는 브라우저 token 전달, Resource Server 호출 주체, server-side 상태, Resource Server의 검증 대상, CSRF 처리 위치를 확인한다. 브라우저가 access token을 받나 SPA : o Mediator : o BFF : x Forward-Auth : x 브라우저가 보호 자원을 직접 부르나 SPA : o Mediator : o BFF : x Forward-Auth : x server-side token 상태가 있나 SPA : x Mediator : o BFF : o Forward-Auth : proxy session 보호 자원이 무엇을 검증하나 SPA : 서명된 JWT Mediator : 서명된 JWT BFF : 서명된 JWT Forward-Auth : edge가 붙인 헤더 cookie가 credential이면 CSRF 검증이 어디에 붙나 SPA : 해당 없음 Mediator : session endpoint BFF : 상태 변경 endpoint Forward-Auth : proxy cookie 기준 호출 주체와 credential 저장 방식을 정한 뒤에는 401/403, token 갱신 실패, logout을 어느 계층에서 처리할지 정한다." - generic [ref=f15e120]: - button "위로" [disabled] [ref=f15e121] - button "아래로" [ref=f15e122] - button "삭제" [ref=f15e123] - generic [ref=f15e124]: - generic [ref=f15e125]: - generic [ref=f15e126]: 규칙 2 제목 - textbox "규칙 2 제목" [ref=f15e127]: 피해야 할 조건을 먼저 확인한다 - generic [ref=f15e128]: - generic [ref=f15e129]: 규칙 2 본문 - textbox "규칙 2 본문" [ref=f15e130]: 정책상 브라우저에 token을 둘 수 없으면 memory에만 두는 보관은 답이 아니다. backend 직접 경로나 헤더 덮어쓰기를 닫을 수 없으면 edge에 인증을 맡기지 않는다. 이 조건에 걸리면 다른 항목은 볼 필요가 없다. - generic [ref=f15e131]: - button "위로" [ref=f15e132] - button "아래로" [ref=f15e133] - button "삭제" [ref=f15e134] - generic [ref=f15e135]: - generic [ref=f15e136]: - generic [ref=f15e137]: 규칙 3 제목 - textbox "규칙 3 제목" [ref=f15e138]: 선택 조건과 운영 부담을 함께 기록한다 - generic [ref=f15e139]: - generic [ref=f15e140]: 규칙 3 본문 - textbox "규칙 3 본문" [ref=f15e141]: 선택 결과만 적지 않고 어떤 요구에서 해당 패턴을 선택했는지와 적용하기 어려운 조건도 함께 기록한다. - generic [ref=f15e142]: - button "위로" [ref=f15e143] - button "아래로" [ref=f15e144] - button "삭제" [ref=f15e145] - generic [ref=f15e146]: - generic [ref=f15e147]: - generic [ref=f15e148]: 규칙 4 제목 - textbox "규칙 4 제목" [ref=f15e149]: 이름으로 운영 속성을 추정하지 않는다 - generic [ref=f15e150]: - generic [ref=f15e151]: 규칙 4 본문 - textbox "규칙 4 본문" [ref=f15e152]: BFF나 forward-auth라는 이름은 배치를 말할 뿐이다. 공유 저장소와 장애 복구, session failover, secret 교체가 갖춰져 있는지는 매번 따로 확인한다. - generic [ref=f15e153]: - button "위로" [ref=f15e154] - button "아래로" [ref=f15e155] - button "삭제" [ref=f15e156] - generic [ref=f15e157]: - generic [ref=f15e158]: - generic [ref=f15e159]: 규칙 5 제목 - textbox "규칙 5 제목" [ref=f15e160]: 옮기는 것은 업그레이드가 아니다 - generic [ref=f15e161]: - generic [ref=f15e162]: 규칙 5 본문 - textbox "규칙 5 본문" [ref=f15e163]: 패턴을 바꾸면 credential을 저장하고 전달하고 검증하는 주체도 함께 바뀐다. edge header가 계속 늘어나 애플리케이션 도메인 정보까지 전달해야 한다면 BFF에서 인가와 API 조합을 처리하는 구성을 다시 검토할 수 있다. - generic [ref=f15e164]: - button "위로" [ref=f15e165] - button "아래로" [disabled] [ref=f15e166] - button "삭제" [ref=f15e167] - button "규칙 추가" [ref=f15e168] - group "적용 조건" [ref=f15e169]: - generic [ref=f15e171]: - generic [ref=f15e172]: - generic [ref=f15e173]: 적용 조건 1 - textbox "적용 조건 1" [ref=f15e174]: 인증 구조를 처음 고를 때 - generic [ref=f15e175]: - button "위로" [disabled] [ref=f15e176] - button "아래로" [ref=f15e177] - button "삭제" [ref=f15e178] - generic [ref=f15e179]: - generic [ref=f15e180]: - generic [ref=f15e181]: 적용 조건 2 - textbox "적용 조건 2" [ref=f15e182]: 한 구조에서 다른 구조로 옮기려 할 때 - generic [ref=f15e183]: - button "위로" [ref=f15e184] - button "아래로" [ref=f15e185] - button "삭제" [ref=f15e186] - generic [ref=f15e187]: - generic [ref=f15e188]: - generic [ref=f15e189]: 적용 조건 3 - textbox "적용 조건 3" [ref=f15e190]: 구조를 문서로 비교할 때 - generic [ref=f15e191]: - button "위로" [ref=f15e192] - button "아래로" [ref=f15e193] - button "삭제" [ref=f15e194] - generic [ref=f15e195]: - generic [ref=f15e196]: - generic [ref=f15e197]: 적용 조건 4 - textbox "적용 조건 4" [ref=f15e198]: 이름만 보고 고른 구조를 다시 검토할 때 - generic [ref=f15e199]: - button "위로" [ref=f15e200] - button "아래로" [disabled] [ref=f15e201] - button "삭제" [ref=f15e202] - button "적용 조건 추가" [ref=f15e203] - group "예외" [ref=f15e204]: - generic [ref=f15e206]: - generic [ref=f15e207]: - generic [ref=f15e208]: 예외 1 - textbox "예외 1" [ref=f15e209]: 요구가 하나로 좁혀지면 비교가 필요 없다. 브라우저에 token을 둘 수 없고 backend가 API를 조합해야 하면 선택지는 하나다. - generic [ref=f15e210]: - button "위로" [disabled] [ref=f15e211] - button "아래로" [ref=f15e212] - button "삭제" [ref=f15e213] - generic [ref=f15e214]: - generic [ref=f15e215]: - generic [ref=f15e216]: 예외 2 - textbox "예외 2" [ref=f15e217]: 학습이나 시연이 목적이면 운영 속성 비교를 하지 않아도 된다. 그때는 학습 환경이라고 문서에 적어 둔다. - generic [ref=f15e218]: - button "위로" [ref=f15e219] - button "아래로" [disabled] [ref=f15e220] - button "삭제" [ref=f15e221] - button "예외 추가" [ref=f15e222] - group "예시" [ref=f15e223]: - generic [ref=f15e225]: - generic [ref=f15e226]: - generic [ref=f15e227]: 예시 1 - textbox "예시 1" [ref=f15e228]: "SPA : 브라우저가 code 교환과 token 보관, API 호출을 모두 맡는다" - generic [ref=f15e229]: - button "위로" [disabled] [ref=f15e230] - button "아래로" [ref=f15e231] - button "삭제" [ref=f15e232] - generic [ref=f15e233]: - generic [ref=f15e234]: - generic [ref=f15e235]: 예시 2 - textbox "예시 2" [ref=f15e236]: "Mediator : refresh token은 server에 있고 access token은 응답 본문으로 브라우저에 간다" - generic [ref=f15e237]: - button "위로" [ref=f15e238] - button "아래로" [ref=f15e239] - button "삭제" [ref=f15e240] - generic [ref=f15e241]: - generic [ref=f15e242]: - generic [ref=f15e243]: 예시 3 - textbox "예시 3" [ref=f15e244]: "BFF : server가 code 교환·token 관리·API 호출을 담당하고 브라우저는 session cookie로 BFF를 호출한다" - generic [ref=f15e245]: - button "위로" [ref=f15e246] - button "아래로" [ref=f15e247] - button "삭제" [ref=f15e248] - generic [ref=f15e249]: - generic [ref=f15e250]: - generic [ref=f15e251]: 예시 4 - textbox "예시 4" [ref=f15e252]: "Forward-Auth : edge가 인증하고 upstream은 edge가 붙인 헤더를 본다" - generic [ref=f15e253]: - button "위로" [ref=f15e254] - button "아래로" [disabled] [ref=f15e255] - button "삭제" [ref=f15e256] - button "예시 추가" [ref=f15e257] - generic [ref=f15e258]: - generic [ref=f15e259]: 마지막 검증일 - textbox "마지막 검증일" [ref=f15e260] - region [ref=f15e261]: - generic [ref=f15e262]: - paragraph [ref=f15e263]: LIVE - heading "즉시 미리보기" [level=2] [ref=f15e264] - generic [ref=f15e267]: - generic [ref=f15e268]: - navigation "문서 경로" [ref=f15e269]: - link "Reference" [ref=f15e270] [cursor=pointer]: - /url: /explore/references - generic [ref=f15e271]: / - generic [ref=f15e272]: OAuth/OIDC 인증 경계 - generic [ref=f15e273]: / - link "KeyCloak Patterns" [ref=f15e274] [cursor=pointer]: - /url: /projects/keycloak-patterns - heading "OAuth/OIDC 인증 패턴 선택 기준" [level=1] [ref=f15e275] - paragraph [ref=f15e276]: SPA, Mediator, BFF, OAuth2-Proxy는 브라우저의 access token 사용 여부, Resource Server 호출 주체, server-side 인증 상태, 보호 자원이 검증하는 credential, CSRF 처리 위치가 서로 다르다. 패턴 선택에서는 이 다섯 항목을 요구사항과 운영 환경에 맞춰 비교한다. - generic [ref=f15e277]: - generic [ref=f15e278]: - term [ref=f15e279]: 유형 - definition [ref=f15e280]: Reference - generic [ref=f15e281]: - term [ref=f15e282]: 프로젝트 - definition [ref=f15e283]: KeyCloak Patterns - generic [ref=f15e284]: - term [ref=f15e285]: 게시 - definition [ref=f15e286]: 게시 전 - region [ref=f15e287]: - paragraph [ref=f15e288]: Purpose - heading "이 기준을 쓰는 이유" [level=2] [ref=f15e289] - paragraph [ref=f15e290]: 브라우저에 token이 덜 보이는 순서는 있다. 그 순서를 보안 등급으로 쓰면 판단이 틀린다.BFF는 브라우저 token을 없애지만 server session과 공유 저장소를 만든다. Forward-Auth는 애플리케이션의 token custody를 줄이지만 edge 헤더 신뢰와 network 경계를 만든다. 새로 생긴 쪽을 감당할 수 없는 환경이면 앞 구조가 더 안전하다.번호가 아니라 배치를 본다. - article [ref=f15e291]: - region [ref=f15e292]: - heading "판단 기준" [level=2] [ref=f15e293] - list [ref=f15e294]: - listitem [ref=f15e295]: - generic [ref=f15e296]: "01" - generic [ref=f15e297]: - heading "다섯 항목으로 구조를 비교한다" [level=3] [ref=f15e298] - paragraph [ref=f15e299]: "구조를 비교할 때는 브라우저 token 전달, Resource Server 호출 주체, server-side 상태, Resource Server의 검증 대상, CSRF 처리 위치를 확인한다. 브라우저가 access token을 받나 SPA : o Mediator : o BFF : x Forward-Auth : x 브라우저가 보호 자원을 직접 부르나 SPA : o Mediator : o BFF : x Forward-Auth : x server-side token 상태가 있나 SPA : x Mediator : o BFF : o Forward-Auth : proxy session 보호 자원이 무엇을 검증하나 SPA : 서명된 JWT Mediator : 서명된 JWT BFF : 서명된 JWT Forward-Auth : edge가 붙인 헤더 cookie가 credential이면 CSRF 검증이 어디에 붙나 SPA : 해당 없음 Mediator : session endpoint BFF : 상태 변경 endpoint Forward-Auth : proxy cookie 기준 호출 주체와 credential 저장 방식을 정한 뒤에는 401/403, token 갱신 실패, logout을 어느 계층에서 처리할지 정한다." - listitem [ref=f15e300]: - generic [ref=f15e301]: "02" - generic [ref=f15e302]: - heading "피해야 할 조건을 먼저 확인한다" [level=3] [ref=f15e303] - paragraph [ref=f15e304]: 정책상 브라우저에 token을 둘 수 없으면 memory에만 두는 보관은 답이 아니다. backend 직접 경로나 헤더 덮어쓰기를 닫을 수 없으면 edge에 인증을 맡기지 않는다. 이 조건에 걸리면 다른 항목은 볼 필요가 없다. - listitem [ref=f15e305]: - generic [ref=f15e306]: "03" - generic [ref=f15e307]: - heading "선택 조건과 운영 부담을 함께 기록한다" [level=3] [ref=f15e308] - paragraph [ref=f15e309]: 선택 결과만 적지 않고 어떤 요구에서 해당 패턴을 선택했는지와 적용하기 어려운 조건도 함께 기록한다. - listitem [ref=f15e310]: - generic [ref=f15e311]: "04" - generic [ref=f15e312]: - heading "이름으로 운영 속성을 추정하지 않는다" [level=3] [ref=f15e313] - paragraph [ref=f15e314]: BFF나 forward-auth라는 이름은 배치를 말할 뿐이다. 공유 저장소와 장애 복구, session failover, secret 교체가 갖춰져 있는지는 매번 따로 확인한다. - listitem [ref=f15e315]: - generic [ref=f15e316]: "05" - generic [ref=f15e317]: - heading "옮기는 것은 업그레이드가 아니다" [level=3] [ref=f15e318] - paragraph [ref=f15e319]: 패턴을 바꾸면 credential을 저장하고 전달하고 검증하는 주체도 함께 바뀐다. edge header가 계속 늘어나 애플리케이션 도메인 정보까지 전달해야 한다면 BFF에서 인가와 API 조합을 처리하는 구성을 다시 검토할 수 있다. - region [ref=f15e320]: - heading "적용할 때" [level=2] [ref=f15e321] - list [ref=f15e322]: - listitem [ref=f15e323]: 인증 구조를 처음 고를 때 - listitem [ref=f15e324]: 한 구조에서 다른 구조로 옮기려 할 때 - listitem [ref=f15e325]: 구조를 문서로 비교할 때 - listitem [ref=f15e326]: 이름만 보고 고른 구조를 다시 검토할 때 - region [ref=f15e327]: - heading "예외와 주의" [level=2] [ref=f15e328] - list [ref=f15e329]: - listitem [ref=f15e330]: 요구가 하나로 좁혀지면 비교가 필요 없다. 브라우저에 token을 둘 수 없고 backend가 API를 조합해야 하면 선택지는 하나다. - listitem [ref=f15e331]: 학습이나 시연이 목적이면 운영 속성 비교를 하지 않아도 된다. 그때는 학습 환경이라고 문서에 적어 둔다. - region [ref=f15e332]: - heading "예시" [level=2] [ref=f15e333] - list [ref=f15e334]: - listitem [ref=f15e335]: "SPA : 브라우저가 code 교환과 token 보관, API 호출을 모두 맡는다" - listitem [ref=f15e336]: "Mediator : refresh token은 server에 있고 access token은 응답 본문으로 브라우저에 간다" - listitem [ref=f15e337]: "BFF : server가 code 교환·token 관리·API 호출을 담당하고 브라우저는 session cookie로 BFF를 호출한다" - listitem [ref=f15e338]: "Forward-Auth : edge가 인증하고 upstream은 edge가 붙인 헤더를 본다" - paragraph [ref=f15e339]: 마지막 검증 - region [ref=f15e340]: - paragraph [ref=f15e341]: Relations - heading "이 기록과 연결된 맥락" [level=2] [ref=f15e342] - list [ref=f15e343]: - listitem [ref=f15e344]: - link "브라우저가 code 교환과 token 보관, API 호출을 모두 맡는다. SPA에서 토큰을 직접 관리하면서 드러난 Browser Credential 경계" [ref=f15e345] [cursor=pointer]: - /url: /cases/spa-browser-credential-boundary - generic [ref=f15e346]: 브라우저가 code 교환과 token 보관, API 호출을 모두 맡는다. - strong [ref=f15e347]: SPA에서 토큰을 직접 관리하면서 드러난 Browser Credential 경계 - generic [ref=f15e348]: ↗ - listitem [ref=f15e349]: - link "mediator가 refresh token을 관리하고 브라우저가 access token으로 API를 직접 호출하는 구성을 확인했다. Refresh Token 관리만 서버로 이전, Access Token은 여전히 Browser에 노출" [ref=f15e350] [cursor=pointer]: - /url: /cases/split-custody-access-token - generic [ref=f15e351]: mediator가 refresh token을 관리하고 브라우저가 access token으로 API를 직접 호출하는 구성을 확인했다. - strong [ref=f15e352]: Refresh Token 관리만 서버로 이전, Access Token은 여전히 Browser에 노출 - generic [ref=f15e353]: ↗ - listitem [ref=f15e354]: - link "BFF가 code 교환, token 보관, Resource Server 호출을 모두 처리하는 구성을 확인했다. Browser Token을 없애면서 BFF에 Session과 CSRF 책임이 생긴 과정" [ref=f15e355] [cursor=pointer]: - /url: /cases/bff-session-csrf-responsibility - generic [ref=f15e356]: BFF가 code 교환, token 보관, Resource Server 호출을 모두 처리하는 구성을 확인했다. - strong [ref=f15e357]: Browser Token을 없애면서 BFF에 Session과 CSRF 책임이 생긴 과정 - generic [ref=f15e358]: ↗ - listitem [ref=f15e359]: - link "인증이 edge로 가면 보호 자원이 검증하는 것이 JWT에서 헤더로 바뀐다. Forward-Auth에서 Client가 보낸 Identity Header를 신뢰하면 안 되는 이유" [ref=f15e360] [cursor=pointer]: - /url: /cases/identity-header-trust - generic [ref=f15e361]: 인증이 edge로 가면 보호 자원이 검증하는 것이 JWT에서 헤더로 바뀐다. - strong [ref=f15e362]: Forward-Auth에서 Client가 보낸 Identity Header를 신뢰하면 안 되는 이유 - generic [ref=f15e363]: ↗ - complementary [ref=f15e364]: - heading "작업 상태" [level=2] [ref=f15e365] - status "편집 상태" [ref=f15e366]: 저장됨 - generic [ref=f15e367]: - generic [ref=f15e368]: - term [ref=f15e369]: 저장 버전 - definition [ref=f15e370]: "11" - generic [ref=f15e371]: - term [ref=f15e372]: 종류 - definition [ref=f15e373]: REFERENCE - paragraph [ref=f15e374]: 불완전한 초안도 저장할 수 있습니다. Ctrl+S 로도 저장합니다. 게시를 누르면 채워야 할 칸을 그 자리에 표시합니다. - generic [ref=f15e375]: - button "저장" [disabled] [ref=f15e376] - button "게시" [ref=f15e377] - paragraph [ref=f15e378]: 버전 11으로 저장했습니다.