103 lines
6.4 KiB
Markdown
103 lines
6.4 KiB
Markdown
---
|
|
id: 66c18e42-116c-459f-86bd-b7e4bf394866
|
|
kind: REFERENCE
|
|
slug: oauth-token-application-session-boundary
|
|
title: OAuth Token과 Application Session을 구분하는 기준
|
|
topic: OAuth/OIDC 인증 경계
|
|
project: KeyCloak Patterns
|
|
status: 게시 전
|
|
version: 11
|
|
studio: "https://hyeonworks.com/studio/documents/66c18e42-116c-459f-86bd-b7e4bf394866/edit"
|
|
---
|
|
|
|
# OAuth Token과 Application Session을 구분하는 기준
|
|
|
|
IdP의 SSO session, access token, refresh token, 애플리케이션 session cookie, proxy session cookie는 만든 주체도 소비자도 수명도 다르다. 다섯을 로그인 상태 하나로 부르면 무엇이 만료됐고 무엇을 지워야 하는지 말할 수 없게 된다.
|
|
|
|
## 관계
|
|
|
|
- **SPA에서 토큰을 직접 관리하면서 드러난 Browser Credential 경계**
|
|
JavaScript memory의 OAuth token과 Keycloak SSO session을 구분한 Case다.
|
|
- **Mediator가 Refresh Token을 관리하고 Access Token을 Browser에 전달하는 구조**
|
|
같은 요청 안에서 session cookie와 access token이 함께 움직인다.
|
|
- **BFF에서 OAuth Token을 관리할 때 Session과 CSRF를 처리한 과정**
|
|
BFF에서는 session cookie, JavaScript가 읽는 CSRF token, server-side OAuth token을 각각 다른 용도로 사용한다.
|
|
- **Forward-Auth에서 Client가 보낸 Identity Header를 신뢰하면 안 되는 이유**
|
|
Forward-Auth에서는 upstream이 JWT를 직접 검증하지 않고 proxy session을 기반으로 edge가 만든 identity header를 사용한다.
|
|
|
|
## 목적
|
|
|
|
네 구조를 다 실행해 보면 응답에는 모두 같은 사용자 이름이 나오게 되어서 같은 인증 정보라고 묶기 쉽다.
|
|
|
|
그런데 값이 들어온 곳을 따라가 보면 어떤 때는 JWT 안의 claim이고 어떤 때는 proxy가 만든 헤더다. 둘을 다 로그인 상태라고 부르게 되면 서명을 검증한 것인지 헤더를 확인한 것인지 문장만 봐서는 구분할 수 없게 된다.
|
|
|
|
로그아웃과 만료 처리는 credential마다 다르다. 어떤 상태를 삭제하거나 만료시킬지 정하려면 IdP SSO session, OAuth token, application session을 구분해서 다뤄야 한다.
|
|
|
|
## 규칙
|
|
|
|
### 1. 다섯 상태에 각각 다른 이름을 쓴다
|
|
|
|
IdP SSO session, OAuth access token, OAuth refresh token, 애플리케이션 session cookie, proxy session cookie는 서로 다른 것이라서 문서와 코드, 로그에서 같은 이름을 돌려 쓰지 않는다.
|
|
|
|
로그와 진단 정보에서도 `로그인 상태`라는 표현만 쓰지 않고 실제 session 또는 token 종류를 기록한다.
|
|
|
|
### 2. 만든 주체와 주된 소비자로 구분한다
|
|
|
|
access token은 IdP가 만들고 Resource Server가 소비하게 되고, 애플리케이션 session cookie는 애플리케이션이 만들어 자기 로그인 상태를 찾는 데 쓰게 되며, proxy session cookie는 proxy의 auth endpoint에만 제시된다.
|
|
|
|
화면에 같은 사용자 이름이 보이더라도 credential을 발급한 주체와 검증하는 주체가 다르면 별도의 상태로 다룬다.
|
|
|
|
### 3. cookie가 token을 담고 있다고 쓰지 않는다
|
|
|
|
애플리케이션 session cookie는 server-side 상태를 찾는 열쇠다. 실제 access token과 refresh token은 별도 store에 있어서 cookie 안에는 없다.
|
|
|
|
proxy session cookie는 같은 모델이 아니다. 서버에 상태를 두지 않고 최소 정보를 cookie 자체에 담아 proxy가 검증하는 구성일 수 있다. 두 cookie를 같은 문장으로 설명하지 않는다.
|
|
|
|
cookie를 token map의 직렬화라고 설명하게 되면 구현 설명이 틀리게 되고, 그 store를 어디에 둘지가 별도 문제라는 것도 함께 가려지게 된다.
|
|
|
|
### 4. 브라우저에 없다는 말의 대상을 밝힌다
|
|
|
|
브라우저 JavaScript에 OAuth token을 전달하지 않는 구조에서도 인증 상태는 존재한다. BFF의 HttpOnly session cookie나 IdP 도메인의 SSO cookie는 각각 별도로 유지될 수 있다.
|
|
|
|
무엇이 없는지를 적지 않으면 브라우저에 인증 상태가 아예 없다는 뜻으로 읽힌다.
|
|
|
|
### 5. 영구 저장소에 없는 것과 실행 중에 없는 것을 나눈다
|
|
|
|
OAuth token을 JavaScript memory에만 보관하면 Web Storage에 지속적으로 저장하지는 않는다. 실행 중 같은 origin의 script가 응답이나 지역 변수에 접근하는 문제는 별도다.
|
|
|
|
두 문장을 같은 증거로 쓰게 되면 XSS 위험이 줄었다는 잘못된 결론이 나오게 된다.
|
|
|
|
### 6. 로그아웃 범위를 상태별로 적는다
|
|
|
|
애플리케이션 상태를 지우는 것과 IdP session을 끝내는 것은 다르고, 이미 발급된 self-contained JWT는 만료 전까지 API에서 계속 통하게 된다.
|
|
|
|
self-contained JWT를 stateless하게 검증하면서 denylist나 introspection을 사용하지 않는 구성에서는 애플리케이션 logout만으로 이미 발급된 access token을 즉시 무효화할 수 없다. 이 경우 짧은 access token TTL을 사용해 유효 시간을 제한한다.
|
|
|
|
### 7. Logout 대상 credential을 구체적으로 적는다
|
|
|
|
SPA의 JavaScript memory를 초기화해도 Keycloak SSO session이 유효하면 다음 authorization request에서 다시 인증 화면을 생략할 수 있다.
|
|
|
|
logout에서는 application session과 authorized client를 각각 어떻게 정리할지 명시한다.
|
|
|
|
## 적용 조건
|
|
|
|
- 인증 상태를 표나 문서로 정리할 때
|
|
- 로그아웃과 만료 동작을 설계할 때
|
|
- 브라우저가 어떤 credential을 저장하거나 전송하는지 설명할 때
|
|
- 여러 구조를 같은 항목으로 비교할 때
|
|
|
|
## 예외
|
|
|
|
- 한 요청 안에서 어느 상태를 말하는지 문맥으로 이미 분명하면 짧은 이름을 쓸 수 있다. 그때도 문서에서 처음 나올 때는 전체 이름을 적어 둔다.
|
|
- IdP를 쓰지 않고 애플리케이션이 자체 로그인만 하는 구조에는 SSO session과 access token, refresh token이 없다.
|
|
|
|
## 예시
|
|
|
|
- IdP SSO session : IdP 도메인의 cookie이고 애플리케이션 memory와 별개다
|
|
- access token : IdP가 만들고 Resource Server가 서명과 issuer, audience를 검증한다
|
|
- refresh token : 새 access token을 받는 장기 credential이다
|
|
- 애플리케이션 session cookie : server-side 로그인 상태를 찾는 열쇠다
|
|
- proxy session cookie : proxy의 auth endpoint에 제시하는 최소 상태다
|
|
- CSRF token : cookie가 자동으로 붙는 상태 변경 요청의 의도를 확인한다
|
|
- identity header : edge가 확인한 사용자 정보의 투영이고 JWT가 아니다
|