refactor: 문서 개선 중
This commit is contained in:
+1
-1
@@ -119,6 +119,6 @@ AP2에서는 mediator가 token을 받고 API는 브라우저가 부른다. AP3
|
||||
|
||||
confidential client는 여기에 클라이언트 인증을 더한다. AP3의 `bff-confidential`은 `client_secret_basic`으로 자기 클라이언트를 인증하면서 PKCE S256도 함께 쓴다. Spring Security에서는 authorization request를 만드는 resolver에 `OAuth2AuthorizationRequestCustomizers.withPkce()`를 장착한다. 그러면 프레임워크가 `state`와 verifier를 만든다.
|
||||
|
||||
클라이언트 설정에 S256을 강제하는 속성이 없고, 테스트도 authorization request의 challenge를 검사하지 않는다. Authorization Code Flow를 쓴다는 것까지는 확인했고, PKCE S256이 고정됐는지는 확인하지 않았다.
|
||||
반면 AP2의 `token-mediating-confidential`은 client 설정에서 S256을 강제하지 않고 AP2 E2E도 authorization request의 challenge를 검사하지 않는다. 따라서 AP2는 Authorization Code를 사용하는 confidential client라는 사실까지 확인했으며, PKCE S256이 고정되었다고 기록하지 않는다.
|
||||
|
||||
<!-- body:end -->
|
||||
|
||||
+6
-10
@@ -10,9 +10,13 @@ status: 게시 전
|
||||
version: 4
|
||||
basisVersion: Keycloak 26.7.0 · Spring Security OAuth2 Resource Server
|
||||
studio: "https://hyeonworks.com/studio/documents/87000d59-b69f-4010-9481-0b71c8bde32d/edit"
|
||||
assets:
|
||||
- key: bearer-jwt-validation-chain
|
||||
file: ../../../final/assets/bearer-jwt-validation-chain/bearer-jwt-validation-chain.svg
|
||||
sourceRevision: keycloak-patterns-lab@2026-08
|
||||
source:
|
||||
- final/document.md#선택의-이유와-지킨-경계-ap1
|
||||
- final/document.md#선택이-코드와-흐름에-반영되는-방식-ap1-완주
|
||||
---
|
||||
|
||||
# Bearer JWT가 인증된 principal이 되기까지
|
||||
@@ -47,17 +51,9 @@ Spring이 받는 것은 이 헤더에 실려 온 문자열 그대로다. 요청
|
||||
|
||||
## 변환 순서
|
||||
|
||||
직접 만든 코드가 지나는 순서는 다음과 같다.
|
||||
검증과 변환은 다음 순서로 이어진다.
|
||||
|
||||
```text label="raw Bearer JWT가 principal이 되기까지"
|
||||
raw Bearer JWT
|
||||
→ NimbusJwtDecoder(JWK signature)
|
||||
→ default issuer + timestamp validators
|
||||
→ AudienceValidator("keycloak-pattern-api")
|
||||
→ validated Jwt
|
||||
→ KeycloakRealmRoleConverter
|
||||
→ authenticated principal + ROLE_* authorities
|
||||
```
|
||||

|
||||
|
||||
헤더를 꺼내 JWT 인증 제공자에 넘기고 설정된 디코더를 부르는 일은 Spring OAuth2 Resource Server가 한다. 저장소의 코드는 Spring 내부 필터를 직접 만들지 않으므로, 이 순서에는 설정 DSL(Domain Specific Language, 설정 전용 문법)이 붙여 주는 부분과 직접 만들어 끼운 빈이 함께 들어 있다.
|
||||
|
||||
|
||||
+1
-1
@@ -43,7 +43,7 @@ source:
|
||||
| Local Storage | 유지 | 읽는다 | 붙지 않는다 |
|
||||
| HttpOnly 쿠키 | 만료까지 유지 | 읽지 못한다 | 붙는다 |
|
||||
|
||||
네 곳 가운데 쿠키만 요청에 자동으로 붙기 때문에, 쿠키를 자격 증명으로 쓰면 그 요청이 사용자가 의도한 것인지 확인하는 CSRF(Cross-Site Request Forgery, 사이트 간 요청 위조) 검증이 따라붙는다.
|
||||
네 곳 가운데 쿠키만 요청에 자동으로 붙기 때문에, 쿠키를 자격 증명으로 쓰면 공격 사이트가 쿠키만 이용해 만든 cross-site forged request와 애플리케이션이 anti-CSRF token을 가지고 만든 요청을 구분하는 CSRF(Cross-Site Request Forgery, 사이트 간 요청 위조) 검증이 따라붙는다.
|
||||
|
||||
## userStore와 stateStore를 나눈다
|
||||
|
||||
|
||||
+2
-2
@@ -20,7 +20,7 @@ source:
|
||||
|
||||
# Cookie로 인증하는 요청에서 CSRF token이 하는 일
|
||||
|
||||
세션 쿠키는 브라우저가 요청마다 자동으로 붙이기 때문에, 상태를 바꾸는 요청이 사용자가 의도한 것인지 서버가 따로 확인해야 한다. CSRF(Cross-Site Request Forgery, 사이트 간 요청 위조) 토큰이 그 확인을 맡고, SameSite는 브라우저가 쿠키를 언제 보낼지 정하는 별도의 정책이다.
|
||||
세션 쿠키는 브라우저가 요청마다 자동으로 붙이기 때문에, 상태를 바꾸는 요청에는 쿠키만으로 만든 cross-site forged request를 구분할 별도 검증 값이 필요하다. CSRF(Cross-Site Request Forgery, 사이트 간 요청 위조) 토큰은 예상한 anti-CSRF token이 함께 온 요청인지 검사하고, SameSite는 브라우저가 쿠키를 언제 보낼지 정하는 별도의 정책이다.
|
||||
|
||||
## 관계
|
||||
|
||||
@@ -100,7 +100,7 @@ theme=dark
|
||||
|
||||
## SameSite가 정하는 것과 CSRF token이 정하는 것
|
||||
|
||||
SameSite는 쿠키를 다른 사이트로 보낼지 브라우저가 정하는 정책이고, CSRF 토큰은 상태를 바꾸는 요청이 사용자의 의도인지 서버가 검증하는 애플리케이션 규약이다.
|
||||
SameSite는 쿠키를 다른 사이트로 보낼지 브라우저가 정하는 정책이고, CSRF 토큰은 cookie가 자동 첨부되는 상태 변경 요청에 별도 검증 값을 요구해 cross-site forged request를 구분하는 애플리케이션 규약이다.
|
||||
|
||||
| | SameSite | CSRF 토큰 |
|
||||
|---|---|---|
|
||||
|
||||
+5
-9
@@ -10,6 +10,9 @@ status: 게시 전
|
||||
version: 4
|
||||
basisVersion: Keycloak 26.7.0 identity brokering
|
||||
studio: "https://hyeonworks.com/studio/documents/d99fdec9-fe9e-4e0f-a50b-6fb9b9ed5719/edit"
|
||||
assets:
|
||||
- key: idp-broker-upstream-downstream-boundary
|
||||
file: ../../../final/assets/idp-broker-upstream-downstream-boundary/idp-broker-upstream-downstream-boundary.svg
|
||||
sourceRevision: keycloak-patterns-lab@2026-08
|
||||
source:
|
||||
- final/document.md#선택이-코드와-흐름에-반영되는-방식-google-login
|
||||
@@ -36,16 +39,9 @@ source:
|
||||
|
||||
사용자가 브로커 로그인 화면에서 어느 외부 IdP로 로그인할지 고르면 인증 왕복이 두 번 일어난다. 앞의 왕복은 브로커와 외부 IdP 사이에서, 뒤의 왕복은 애플리케이션과 브로커 사이에서 일어난다. 브로커보다 앞에 있는 외부 IdP 쪽을 upstream이라고 부른다.
|
||||
|
||||
먼저 브라우저가 외부 IdP에 authorization 요청을 보내고, 브로커는 돌아온 응답을 검증해 자기 realm의 사용자와 연결한다. 그다음 애플리케이션으로 나가는 값은 브로커가 다시 만든다. 무엇이 무엇으로 바뀌는지 순서로 적으면 이렇다.
|
||||
먼저 브라우저가 외부 IdP에 authorization 요청을 보내고, 브로커는 돌아온 응답을 검증해 자기 realm의 사용자와 연결한다. 그다음 애플리케이션으로 나가는 값은 브로커가 다시 만든다. Upstream IdP와 애플리케이션 경계는 다음처럼 이어진다.
|
||||
|
||||
```text label="brokering 변환 순서"
|
||||
Google identity assertion
|
||||
→ Keycloak broker validation
|
||||
→ provider alias + upstream sub로 account identity 결정
|
||||
→ Keycloak local user/session
|
||||
→ Keycloak authorization code
|
||||
→ AP1·AP2·AP3·AP4 중 선택한 downstream 경계
|
||||
```
|
||||

|
||||
|
||||
외부 IdP가 보낸 것은 첫 줄의 `Google identity assertion` 하나이고, 그 아래 `Keycloak local user/session`과 `Keycloak authorization code`는 브로커가 만든다.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user