feat(ap2): hand off access token only
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
# AP2 · Token-Mediating Backend
|
||||
|
||||
## 책임 경계
|
||||
|
||||
1. 브라우저는 Spring backend의 `/oauth2/authorization/keycloak`로 로그인을
|
||||
시작합니다.
|
||||
2. Keycloak은 authorization code를 Spring callback으로 전달합니다.
|
||||
3. confidential client인 Spring backend가 client secret을 사용해 code를
|
||||
교환하고 access/refresh token을 `OAuth2AuthorizedClientService`에
|
||||
보관합니다.
|
||||
4. 브라우저가 `/token/access`를 호출하면 backend는 현재 access token,
|
||||
token type, 만료 시각만 `Cache-Control: no-store`로 반환합니다.
|
||||
5. 브라우저는 전달받은 access token을 메모리에서만 사용해 Resource
|
||||
Server를 직접 호출합니다.
|
||||
|
||||
refresh token은 브라우저 응답, Web Storage, cookie에 전달되지 않습니다.
|
||||
access token이 만료되면 `OAuth2AuthorizedClientManager`가 서버에 보관된
|
||||
refresh token으로 갱신한 뒤 새 access token만 전달할 수 있습니다.
|
||||
|
||||
## 확인할 보안 속성
|
||||
|
||||
- Keycloak client는 `client_secret_basic`을 사용하는 confidential client입니다.
|
||||
- Resource Server는 서명, issuer, timestamp와 함께
|
||||
`aud=keycloak-pattern-api`를 검증합니다.
|
||||
- CORS는 AP2 UI origin인 `http://localhost:8082`의 `GET`만 허용합니다.
|
||||
- access-token 응답에는 `refresh_token` 필드가 없고 `no-store`가 적용됩니다.
|
||||
- 브라우저 cookie에는 HttpOnly, SameSite=Lax인 `AP2_SESSION` 식별자만
|
||||
저장됩니다. 실제 OAuth token은 session cookie 안에 들어가지 않습니다.
|
||||
|
||||
## 실행
|
||||
|
||||
```bash
|
||||
./scripts/verify-pattern2.sh
|
||||
```
|
||||
|
||||
검증은 실제 Keycloak 로그인 후 서버 token 보관 여부, access-only 응답의
|
||||
필드 집합과 audience, 브라우저의 직접 Resource Server 호출, Web Storage
|
||||
비사용을 확인합니다.
|
||||
Reference in New Issue
Block a user