feat: 가상화 문서들 추가

This commit is contained in:
DongHyeonka
2026-09-10 08:54:05 +09:00
parent e9f6a93327
commit 43e1aadef0
695 changed files with 153404 additions and 12754 deletions
@@ -12,13 +12,17 @@ verifiedOn: 2026-08-22
studio: "https://hyeonworks.com/studio/documents/bf675775-4f3e-4744-8014-f0efff51422a/edit"
public: "https://hyeonworks.com/cases/spa-browser-credential-boundary"
assets:
- key: ap1-custody-v3-6e0376d2
file: ../../../final/assets/tech-log-studio/ap1-credential-custody.svg
- key: ap1-direct-architecture
file: ../../../final/assets/ap1-direct-architecture/ap1-direct-architecture.svg
- key: ap1-browser-bearer-flow
file: ../../../final/assets/ap1-browser-bearer-flow/ap1-browser-bearer-flow.svg
sourceRevision: keycloak-patterns-lab@2026-08
source:
- final/document.md#검토한-선택지와-막힌-지점-ap1
- final/document.md#선택의-이유와-지킨-경계-ap1
- final/document.md#선택이-코드와-흐름에-반영되는-방식-ap1-완주
- final/document.md#결정이-지켜지는지-확인하는-방법-ap1
- final/document.md#얻은-것-잃은-것-적용하지-않을-때-ap1
---
# SPA에서 OAuth Token을 JavaScript Memory에 보관한 경우
@@ -100,8 +104,7 @@ public client는 브라우저처럼 client secret을 안전하게 숨길 수 없
## SPA가 토큰을 다루는 위치
:::evidence key="ap1-custody-v3-6e0376d2" alt="브라우저 실행 영역 안에 code 교환, access·refresh·ID token 보관, Authorization 헤더 조립 세 상자가 들어 있고 그 영역 전체가 실행 중 XSS가 닿는 범위로 표시된 그림. Keycloak과 Resource Server는 그 밖에 있다." caption=" " zoom="true"
:::
![SPA, Keycloak, 브라우저 JavaScript memory, Resource Server가 왼쪽에서 오른쪽으로 연결된 AP1 직접 인증 아키텍처.](../../../final/assets/ap1-direct-architecture/ap1-direct-architecture.svg)
authorization code 교환, 토큰 보관, `Authorization` 헤더 조립까지 모두 브라우저에서 일어난다. 액세스·리프레시·ID 토큰은 JavaScript 메모리에 있고, Resource Server를 부를 때 쓸 `Authorization` 헤더도 같은 페이지에서 만든다.
@@ -141,7 +144,7 @@ GET http://localhost:8081/api/me
Authorization: Bearer <access-token>
```
API를 부르는 동안에는 액세스 토큰이 요청의 `Authorization` 헤더에도 실린다.
API를 부르는 동안에는 액세스 토큰이 요청의 `Authorization` 헤더에도 실린다. Resource Server가 돌려주는 것은 `subject`·`username`·`issuer`·`audience` 네 필드다.
Resource Server는 `SessionCreationPolicy.STATELESS`로 설정되어 있어 서버에서 지울 애플리케이션 세션이 없고, 이미 발급된 self-contained JWT를 logout 시점에 곧바로 무효화하는 처리도 넣지 않았다. logout은 Keycloak SSO 종료와 SPA의 사용자 제거까지만 하고, 발급된 access JWT를 deny-list로 따로 관리하지는 않는다.
@@ -157,6 +160,8 @@ issuer·audience : 검증
## PKCE가 적용되는 구간
![브라우저 SPA, Keycloak, Resource Server 사이에서 authorization request, callback, token 교환, Bearer API 호출과 JSON 응답이 이어지는 순서도.](../../../final/assets/ap1-browser-bearer-flow/ap1-browser-bearer-flow.svg)
PKCE(Proof Key for Code Exchange)를 쓰면 authorization request에는 `code_challenge`가 들어가고, authorization code를 토큰으로 교환할 때는 원본인 `code_verifier`를 함께 보낸다. 두 값이 맞아야 code를 교환할 수 있다.
```text label="oidc-client-ts가 만드는 authorization request의 핵심 query"
@@ -218,4 +223,4 @@ exact callback만 허용하는 운영 가드레일, 잘못된 redirect를 거부
frontend Nginx에도 `/api/` proxy가 있지만 SPA는 상대 URL이 아니라 absolute URL인 `http://localhost:8081/api/me`를 부른다. 그래서 지금 요청은 브라우저에서 Resource Server로 곧장 나가 CORS allowlist를 거치고, 상대 URL로 Nginx를 통해 불렀다면 이 CORS 경로는 지나지 않았을 것이다.
<!-- body:end -->
<!-- body:end -->