feat: 가상화 문서들 추가
This commit is contained in:
+11
-6
@@ -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"
|
||||
:::
|
||||

|
||||
|
||||
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가 적용되는 구간
|
||||
|
||||

|
||||
|
||||
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 -->
|
||||
|
||||
Reference in New Issue
Block a user