refactor: 문서 개선 중
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
{
|
||||
"kind": "REFERENCE",
|
||||
"title": "OAuth Token과 Application Session을 구분하는 기준",
|
||||
"slug": "oauth-token-application-session-boundary",
|
||||
"summary": "IdP의 SSO session, access token, refresh token, 애플리케이션 session cookie, proxy session cookie는 만든 주체도 소비자도 수명도 다르다. 다섯을 로그인 상태 하나로 부르면 무엇이 만료됐고 무엇을 지워야 하는지 말할 수 없게 된다.",
|
||||
"purpose": "네 구조를 다 실행해 보면 응답에는 모두 같은 사용자 이름이 나오게 되어서 같은 인증 정보라고 묶기 쉽다.\n\n그런데 값이 들어온 곳을 따라가 보면 어떤 때는 JWT 안의 claim이고 어떤 때는 proxy가 만든 헤더다. 둘을 다 로그인 상태라고 부르게 되면 서명을 검증한 것인지 헤더를 확인한 것인지 문장만 봐서는 구분할 수 없게 된다.\n\n로그아웃과 만료 처리는 credential마다 다르다. 어떤 상태를 삭제하거나 만료시킬지 정하려면 IdP SSO session, OAuth token, application session을 구분해서 다뤄야 한다.",
|
||||
"rules": [
|
||||
{
|
||||
"title": "다섯 상태에 각각 다른 이름을 쓴다",
|
||||
"body": "IdP SSO session, OAuth access token, OAuth refresh token, 애플리케이션 session cookie, proxy session cookie는 서로 다른 것이라서 문서와 코드, 로그에서 같은 이름을 돌려 쓰지 않는다.\n\n로그와 진단 정보에서도 `로그인 상태`라는 표현만 쓰지 않고 실제 session 또는 token 종류를 기록한다."
|
||||
},
|
||||
{
|
||||
"title": "만든 주체와 주된 소비자로 구분한다",
|
||||
"body": "access token은 IdP가 만들고 Resource Server가 소비하게 되고, 애플리케이션 session cookie는 애플리케이션이 만들어 자기 로그인 상태를 찾는 데 쓰게 되며, proxy session cookie는 proxy의 auth endpoint에만 제시된다.\n\n화면에 같은 사용자 이름이 보이더라도 credential을 발급한 주체와 검증하는 주체가 다르면 별도의 상태로 다룬다."
|
||||
},
|
||||
{
|
||||
"title": "cookie가 token을 담고 있다고 쓰지 않는다",
|
||||
"body": "애플리케이션 session cookie는 server-side 상태를 찾는 열쇠다. 실제 access token과 refresh token은 별도 store에 있어서 cookie 안에는 없다.\n\nproxy session cookie는 같은 모델이 아니다. 서버에 상태를 두지 않고 최소 정보를 cookie 자체에 담아 proxy가 검증하는 구성일 수 있다. 두 cookie를 같은 문장으로 설명하지 않는다.\n\ncookie를 token map의 직렬화라고 설명하게 되면 구현 설명이 틀리게 되고, 그 store를 어디에 둘지가 별도 문제라는 것도 함께 가려지게 된다."
|
||||
},
|
||||
{
|
||||
"title": "브라우저에 없다는 말의 대상을 밝힌다",
|
||||
"body": "브라우저 JavaScript에 OAuth token을 전달하지 않는 구조에서도 인증 상태는 존재한다. BFF의 HttpOnly session cookie나 IdP 도메인의 SSO cookie는 각각 별도로 유지될 수 있다.\n\n무엇이 없는지를 적지 않으면 브라우저에 인증 상태가 아예 없다는 뜻으로 읽힌다."
|
||||
},
|
||||
{
|
||||
"title": "영구 저장소에 없는 것과 실행 중에 없는 것을 나눈다",
|
||||
"body": "OAuth token을 JavaScript memory에만 보관하면 Web Storage에 지속적으로 저장하지는 않는다. 실행 중 같은 origin의 script가 응답이나 지역 변수에 접근하는 문제는 별도다.\n\n두 문장을 같은 증거로 쓰게 되면 XSS 위험이 줄었다는 잘못된 결론이 나오게 된다."
|
||||
},
|
||||
{
|
||||
"title": "로그아웃 범위를 상태별로 적는다",
|
||||
"body": "애플리케이션 상태를 지우는 것과 IdP session을 끝내는 것은 다르고, 이미 발급된 self-contained JWT는 만료 전까지 API에서 계속 통하게 된다.\n\nself-contained JWT를 stateless하게 검증하면서 denylist나 introspection을 사용하지 않는 구성에서는 애플리케이션 logout만으로 이미 발급된 access token을 즉시 무효화할 수 없다. 이 경우 짧은 access token TTL을 사용해 유효 시간을 제한한다."
|
||||
},
|
||||
{
|
||||
"title": "하나를 지웠다고 다른 하나가 사라졌다고 쓰지 않는다",
|
||||
"body": "SPA의 JavaScript memory를 초기화해도 Keycloak SSO session이 유효하면 다음 authorization request에서 다시 인증 화면을 생략할 수 있다.\n\nlogout에서는 application session과 authorized client를 각각 어떻게 정리할지 명시한다."
|
||||
}
|
||||
],
|
||||
"verifiedOn": null,
|
||||
"applyWhen": [
|
||||
"인증 상태를 표나 문서로 정리할 때",
|
||||
"로그아웃과 만료 동작을 설계할 때",
|
||||
"브라우저에 무엇이 남는지 설명할 때",
|
||||
"여러 구조를 같은 항목으로 비교할 때"
|
||||
],
|
||||
"exceptions": [
|
||||
"한 요청 안에서 어느 상태를 말하는지 문맥으로 이미 분명하면 짧은 이름을 쓸 수 있다. 그때도 문서에서 처음 나올 때는 전체 이름을 적어 둔다.",
|
||||
"IdP를 쓰지 않고 애플리케이션이 자체 로그인만 하는 구조에는 SSO session과 access token, refresh token이 없다."
|
||||
],
|
||||
"examples": [
|
||||
"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가 아니다"
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user