- Authors

- Name
- Youngju Kim
- @fjvbn20031
- 들어가며
- 토큰 수명 설계 원칙
- Rotation + Reuse Detection 메커니즘
- 세션의 3계층 모델 — IdP 세션, 앱 세션, SSO 세션
- Keycloak 세션 설정 상세
- 디바이스별 세션 관리
- 로그아웃과 세션 정리
- BFF(Backend-for-Frontend) 패턴
- 보안 사고 시나리오와 대응
- 안티패턴 모음
- 마치며
- 참고 자료
들어가며
인증 시스템에서 가장 어려운 질문은 "어떻게 로그인시킬까"가 아니라 "로그인 상태를 얼마나, 어떻게 유지할까"입니다. 토큰 수명을 길게 잡으면 사용자 경험은 좋아지지만 탈취 피해가 커지고, 짧게 잡으면 안전해지지만 재로그인 지옥이 펼쳐집니다. 이 긴장을 푸는 표준 도구가 refresh token이고, 그 안전장치가 rotation과 reuse detection입니다.
2026년의 맥락에서 이 주제는 더 중요해졌습니다. OAuth 2.1 draft는 public client의 refresh token에 rotation 또는 sender-constraining을 의무화했고, RFC 9700(OAuth Security BCP)은 그 구체적 구현 요건을 정의합니다. 한편 passkeys가 기본 인증 수단이 되면서 "비밀번호는 안전해졌는데 세션/토큰이 약한 고리"가 되는 역전 현상이 일어나고 있습니다. 공격자는 이제 비밀번호 대신 세션 쿠키와 refresh token을 노립니다. 인포스틸러 멀웨어가 훔치는 것도 바로 이것들입니다.
이 글에서는 토큰 수명 설계 원칙부터 rotation 메커니즘의 내부 동작, IdP/앱/SSO 세션의 3계층 모델, Keycloak의 세션 설정 상세, 그리고 토큰 탈취 사고 발생 시 대응 절차까지를 다룹니다.
토큰 수명 설계 원칙
두 토큰의 역할 분담
┌──────────────────────────────────────────────────────────┐
│ Access Token (AT) │
│ - 용도: API 호출 인가 │
│ - 수명: 5~15분 (짧게!) │
│ - 검증: stateless (서명 검증만, IdP 조회 없음) │
│ - 탈취 시: 수명만큼만 피해. 차단 불가가 전제 │
├──────────────────────────────────────────────────────────┤
│ Refresh Token (RT) │
│ - 용도: 새 AT 발급 (IdP의 token 엔드포인트에서만 사용) │
│ - 수명: idle 수 시간~수 주, max 수 주~수 개월 │
│ - 검증: stateful (IdP가 세션/패밀리 상태를 확인) │
│ - 탈취 시: rotation + reuse detection으로 감지/차단 │
└──────────────────────────────────────────────────────────┘
설계 원칙은 다음 네 가지로 요약됩니다.
- AT는 "차단할 수 없다"고 전제하고 수명으로 피해를 제한합니다. AT가 5분짜리라면 탈취돼도 피해 창은 최대 5분입니다.
- RT는 "탈취된다"고 전제하고 감지 메커니즘을 답니다. rotation + reuse detection이 그 감지기입니다.
- 수명은 위험도에 비례시킵니다. 금융 서비스의 RT와 사내 위키의 RT가 같은 수명일 이유가 없습니다.
- idle과 max를 분리합니다. "안 쓰면 이만큼 후 만료(idle)"와 "아무리 써도 이 시점엔 만료(max)"는 다른 통제입니다.
수명 권장 시작값
| 서비스 유형 | AT | RT idle | RT max | 비고 |
|---|---|---|---|---|
| 금융/결제 | 5분 | 30분 | 8시간 | 재인증 빈도 높음 |
| 일반 B2C 웹/앱 | 10~15분 | 14일 | 90일 | rotation 필수 |
| 사내 업무 시스템 | 10분 | 8시간 | 24시간 | 근무일 단위 |
| 백그라운드 동기화 (offline) | 10분 | 30일 | 180일 | offline 토큰, 별도 감사 |
이 값은 정답이 아니라 출발점입니다. 핵심은 "각 값이 왜 그 값인지"를 설명할 수 있어야 한다는 것입니다.
Rotation + Reuse Detection 메커니즘
기본 동작
rotation은 RT를 사용할 때마다 새 RT를 발급하고 직전 RT를 무효화하는 것입니다. RT가 일회용 티켓이 되는 셈입니다.
시각 클라이언트 IdP
t0 RT1로 갱신 요청 → AT2 + RT2 발급, RT1을 "사용됨"으로 마킹
t1 RT2로 갱신 요청 → AT3 + RT3 발급, RT2를 "사용됨"으로 마킹
t2 RT3로 갱신 요청 → AT4 + RT4 발급, ...
토큰 패밀리와 재사용 감지
같은 최초 인증에서 파생된 RT들의 계보를 토큰 패밀리(token family) 라고 부릅니다. 재사용 감지는 이 패밀리 단위로 동작합니다.
패밀리 F1: RT1 ──> RT2 ──> RT3 (현재 유효)
탈취 시나리오 A: 공격자가 먼저 사용
1. 공격자가 RT2를 탈취해 갱신 → RT3' 획득 (공격자가 최신)
2. 정상 사용자가 RT2로 갱신 시도
3. IdP: "RT2는 이미 사용됨" → 재사용 감지!
4. 패밀리 F1 전체 무효화 (RT3'도 죽음)
5. 양쪽 모두 로그아웃 → 정상 사용자는 재로그인, 공격자는 차단
탈취 시나리오 B: 정상 사용자가 먼저 사용
1. 공격자가 RT2를 탈취 (아직 미사용)
2. 정상 사용자가 RT2로 갱신 → RT3 발급
3. 공격자가 RT2로 갱신 시도 → 재사용 감지! → 패밀리 무효화
어느 쪽이 먼저든, "두 번 쓰인 RT"가 감지되는 순간
패밀리 전체가 죽는다는 것이 핵심입니다.
이 메커니즘의 아름다움은 공격자와 정상 사용자를 구분할 필요가 없다는 점입니다. 누가 도둑인지 몰라도, 충돌이 감지되면 전부 무효화하고 재인증을 요구하면 됩니다. 정상 사용자는 약간의 불편(재로그인)을 겪지만, 공격자는 영구히 차단됩니다.
네트워크 오류와 grace period
현실에서는 정상 클라이언트도 RT를 "두 번" 보낼 수 있습니다. 갱신 요청 후 응답을 못 받고 재시도하는 경우입니다. 이를 위해 짧은 grace period(전송 중복 허용 창, 보통 수 초~수십 초)를 두는 구현이 많습니다. Keycloak은 revokeRefreshToken 활성화 시 refreshTokenMaxReuse(기본 0)로 허용 재사용 횟수를 제어합니다. 0이 가장 안전하며, 클라이언트의 재시도 로직을 멱등하게 만드는 것이 정도(正道)입니다.
# Keycloak: rotation + 재사용 0회 허용 (가장 엄격)
kcadm.sh update realms/myrealm \
-s revokeRefreshToken=true \
-s refreshTokenMaxReuse=0
세션의 3계층 모델 — IdP 세션, 앱 세션, SSO 세션
토큰만 보면 세션 관리의 절반밖에 보지 못한 것입니다. 실제 시스템에는 세 종류의 "로그인 상태"가 공존합니다.
┌───────────────────────────────────────────────────────────────┐
│ 3계층 세션 모델 │
│ │
│ [브라우저] │
│ ├── 앱 세션 A (app-a.example.com의 세션 쿠키) │
│ ├── 앱 세션 B (app-b.example.com의 세션 쿠키) │
│ └── IdP 세션 (idp.example.com의 SSO 쿠키) │
│ │ │
│ ▼ │
│ [IdP 서버] │
│ └── SSO 세션 (서버 측 상태: 어떤 사용자가, 어떤 클라이언트들에, │
│ 언제 인증했는지의 원장) │
│ ├── Client Session A (app-a에 대한 토큰 발급 기록) │
│ └── Client Session B (app-b에 대한 토큰 발급 기록) │
└───────────────────────────────────────────────────────────────┘
| 계층 | 저장 위치 | 수명 주체 | 만료 시 효과 |
|---|---|---|---|
| 앱 세션 | 각 앱의 쿠키/세션 저장소 | 앱 | 그 앱만 로그아웃 |
| IdP 세션(SSO 쿠키) | IdP 도메인 쿠키 | IdP | 새 SSO 로그인 불가, 기존 앱 세션은 유지될 수 있음 |
| SSO 세션(서버 상태) | IdP 서버/DB | IdP | RT 갱신 실패, 신규 토큰 발급 불가 |
실무에서 가장 많은 혼란이 "로그아웃했는데 다른 앱은 왜 로그인되어 있나요?"입니다. 답은 이 3계층이 독립적으로 만료되기 때문입니다. 앱 A에서 로그아웃해도(앱 세션 A 삭제), IdP 세션이 살아 있으면 앱 A에 다시 접근할 때 자동 재로그인됩니다. 반대로 IdP 세션을 죽여도 앱 B의 자체 세션 쿠키가 살아 있으면 앱 B는 계속 동작합니다. 이를 정리하려면 뒤에서 다룰 로그아웃 전파가 필요합니다.
Keycloak 세션 설정 상세
Keycloak은 이 모델을 SSO Session, Client Session, Offline Session으로 구현합니다. Realm Settings의 Sessions와 Tokens 탭에서 설정합니다.
SSO Session
SSO Session Idle: 기본 30분
- 이 시간 동안 세션 활동(토큰 갱신 등)이 없으면 세션 만료
- RT의 실효 idle 수명을 결정 (RT 수명 = min(이 값, client session 값))
SSO Session Max: 기본 10시간
- 활동과 무관하게 최초 인증 후 이 시간이 지나면 세션 만료
- "아무리 열심히 갱신해도 10시간 후엔 재로그인"의 근거
Client Session
Client Session Idle / Client Session Max: 기본 0 (= SSO 값 상속)
- 클라이언트 단위로 더 짧은 토큰 수명을 강제하고 싶을 때 사용
- 예: realm 전체는 idle 30일이지만, 결제 클라이언트만 idle 30분
- 클라이언트의 Advanced Settings에서 개별 재정의도 가능
중요한 동작: refresh token의 만료 시각은 SSO 세션과 클라이언트 세션 중 먼저 끝나는 쪽에 묶입니다. 즉 Keycloak에서 RT 수명은 독립 설정값이 아니라 세션 수명의 파생물입니다. 이 사실을 모르면 "RT 수명을 늘렸는데 적용이 안 돼요" 같은 미스터리에 빠집니다.
Offline Session
백그라운드 동기화처럼 사용자가 브라우저를 닫은 뒤에도 토큰 갱신이 필요한 경우를 위한 별도 트랙입니다. scope에 offline_access를 포함해 요청하면 offline token이 발급됩니다.
Offline Session Idle: 기본 30일
- offline RT를 30일 안에 한 번씩 사용하면 계속 연장
Offline Session Max Limited: 활성화 시 절대 상한 적용
Offline Session Max: 기본 60일
- 갱신 여부와 무관한 절대 만료
offline token은 일반 SSO 세션과 분리되어 관리되며, 사용자가 로그아웃해도 살아남습니다. 강력한 만큼 발급 대상을 엄격히 제한하고(클라이언트 scope 통제), Admin Console의 사용자별 Consents/Sessions에서 주기적으로 감사해야 합니다.
토큰 수명 설정
Access Token Lifespan: 기본 5분 (늘리지 마세요)
Access Token Lifespan For Implicit: 레거시, 무시
Client Login Timeout: 인가 코드 → 토큰 교환의 허용 시간
설정 예시를 kcadm으로 정리하면 다음과 같습니다.
kcadm.sh update realms/myrealm \
-s accessTokenLifespan=600 \
-s ssoSessionIdleTimeout=1209600 \
-s ssoSessionMaxLifespan=7776000 \
-s offlineSessionIdleTimeout=2592000 \
-s offlineSessionMaxLifespanEnabled=true \
-s offlineSessionMaxLifespan=15552000 \
-s revokeRefreshToken=true \
-s refreshTokenMaxReuse=0
(위 예시: AT 10분, SSO idle 14일, SSO max 90일, offline idle 30일, offline max 180일, rotation 활성화.)
디바이스별 세션 관리
한 사용자는 여러 디바이스에서 동시에 로그인합니다. 각 로그인은 독립된 SSO 세션(따라서 독립된 토큰 패밀리)이어야 합니다.
사용자 alice의 세션 목록 (IdP 관점)
┌────────────┬──────────────┬─────────────┬──────────────┐
│ 세션 ID │ 디바이스 │ 시작 │ 마지막 활동 │
├────────────┼──────────────┼─────────────┼──────────────┤
│ sess-a1 │ MacBook/Chrome│ 06-10 09:12 │ 06-12 11:40 │
│ sess-b2 │ iPhone/앱 │ 06-08 20:01 │ 06-12 08:15 │
│ sess-c3 │ 회사 PC/Edge │ 06-11 08:55 │ 06-11 18:02 │
└────────────┴──────────────┴─────────────┴──────────────┘
이 구조가 주는 운영 능력은 다음과 같습니다.
- 세션 목록 표시: "내 계정에서 로그인된 기기" 화면. 사용자가 직접 의심 세션을 종료할 수 있게 합니다.
- 개별 무효화: 분실한 폰의 세션만 종료. 다른 디바이스는 영향 없음.
- 이상 감지의 단위: 동일 패밀리의 RT가 서로 다른 국가 IP에서 사용되면 그 세션만 격리할 수 있습니다.
Keycloak Admin REST API로 세션을 조회/종료할 수 있습니다.
# 사용자 세션 목록 조회
kcadm.sh get users/USER-UUID/sessions -r myrealm
# 특정 세션만 종료
kcadm.sh delete sessions/SESSION-ID -r myrealm
# 사용자의 모든 세션 종료 (모든 디바이스 로그아웃)
kcadm.sh create users/USER-UUID/logout -r myrealm
로그아웃과 세션 정리
로그아웃은 "쿠키 삭제"가 아니라 3계층 세션과 토큰 패밀리를 일관되게 정리하는 분산 트랜잭션입니다. 완전한 로그아웃은 다음을 모두 수행해야 합니다.
1. 앱 세션 삭제 (앱 자신의 세션 쿠키/저장소)
2. IdP 세션 종료 (OIDC RP-Initiated Logout: /logout 엔드포인트)
3. RT 무효화 (token revocation: RFC 7009 /revoke)
4. 다른 앱들에 전파 (Back-Channel Logout: RFC 적용 또는 OIDC 스펙)
전파 메커니즘은 두 가지가 있습니다.
| 방식 | 동작 | 장단점 |
|---|---|---|
| Front-Channel Logout | 브라우저가 각 앱의 logout URL을 iframe 등으로 순회 호출 | 구현 단순 / 브라우저 의존, 3rd-party 쿠키 차단에 취약 |
| Back-Channel Logout | IdP가 각 앱 서버로 logout token(JWT)을 직접 POST | 신뢰성 높음, 2026년 권장 / 앱이 세션-sid 매핑을 유지해야 함 |
Back-Channel Logout을 받는 앱 쪽 책임이 중요합니다. logout token의 서명과 클레임(iss, aud, events, sid)을 검증한 뒤, sid에 해당하는 앱 세션을 실제로 파기해야 합니다. 이 매핑(IdP의 sid → 앱 세션 ID)을 로그인 시점에 저장해 두지 않으면 전파를 받아도 할 수 있는 일이 없습니다.
Back-Channel Logout 흐름
IdP ── POST logout_token(JWT, sid=xyz) ──> App B의 /backchannel-logout
├ 서명/클레임 검증
├ sid=xyz → 앱 세션 s-42 조회
└ s-42 파기, 204 응답
BFF(Backend-for-Frontend) 패턴
SPA의 토큰 관리 문제를 구조적으로 해소하는 패턴입니다. 토큰을 브라우저에 두지 않고, 프런트엔드 전용 백엔드가 토큰의 보관자이자 프록시가 됩니다.
┌─────────┐ HttpOnly 세션 쿠키 ┌─────────────┐ AT/RT 보관 ┌────────┐
│ Browser │ <─────────────────────> │ BFF │ <───────────> │ IdP │
│ (SPA) │ /api/* 프록시 │ (서버 세션) │ └────────┘
└─────────┘ │ │ │ AT 첨부
│ └──────┼──────────────> APIs
└─────────────┘
동작 방식:
- 로그인은 BFF가 confidential client로서 code + PKCE flow를 수행합니다.
- AT/RT는 BFF의 서버 측 세션 저장소(Redis 등)에만 존재합니다.
- 브라우저는 HttpOnly + Secure + SameSite=Strict 쿠키로 BFF와 통신합니다.
- SPA의 API 호출은 BFF가 프록시하며, 이때 AT를 붙입니다. AT 만료 시 BFF가 RT로 조용히 갱신합니다.
| 항목 | 토큰을 브라우저에 둘 때 | BFF |
|---|---|---|
| XSS로 토큰 유출 | 가능 | 불가능 (토큰이 브라우저에 없음) |
| CSRF | 해당 없음 | SameSite + CSRF 토큰으로 방어 필요 |
| rotation 구현 위치 | SPA (탭 간 경합 문제) | BFF (단일 지점, 단순) |
| 운영 비용 | 낮음 | BFF 인프라 추가 |
여러 탭이 동시에 RT 갱신을 시도하며 rotation과 충돌하는 고질적인 SPA 문제(탭 A가 갱신해서 RT가 바뀌었는데 탭 B가 구 RT로 갱신 시도 → 재사용 감지 오발)는 BFF에서 갱신을 단일화하면 자연히 사라집니다. 새로 시작하는 프로젝트라면 BFF를 기본값으로 검토하기를 권합니다.
BFF의 토큰 갱신 핵심부를 Node/Express로 스케치하면 다음과 같습니다. 갱신을 세션 단위 락으로 직렬화하는 부분이 요점입니다.
// BFF의 토큰 갱신 미들웨어 (개념 스케치)
import { Issuer } from 'openid-client';
const sessionLocks = new Map(); // 세션별 갱신 직렬화
async function ensureFreshToken(req, res, next) {
const session = await store.get(req.sessionId);
if (!session) return res.status(401).end();
const skewMs = 30_000; // 만료 30초 전부터 선제 갱신
if (session.atExpiresAt - Date.now() > skewMs) {
req.accessToken = session.accessToken;
return next();
}
// 같은 세션의 동시 갱신을 하나로 직렬화 (rotation 오발 방지)
let lock = sessionLocks.get(req.sessionId);
if (!lock) {
lock = oidcClient
.refresh(session.refreshToken) // rotation: 새 RT가 돌아옴
.then(async (tokens) => {
await store.update(req.sessionId, {
accessToken: tokens.access_token,
refreshToken: tokens.refresh_token, // 구 RT는 즉시 폐기
atExpiresAt: Date.now() + tokens.expires_in * 1000,
});
return tokens.access_token;
})
.finally(() => sessionLocks.delete(req.sessionId));
sessionLocks.set(req.sessionId, lock);
}
try {
req.accessToken = await lock;
next();
} catch (err) {
await store.destroy(req.sessionId); // 갱신 실패 = 세션 종료
res.status(401).end();
}
}
여러 인스턴스로 BFF를 수평 확장하는 경우에는 위의 인메모리 락 대신 Redis 분산 락(또는 갱신 전용 단일 워커)으로 동일한 직렬화를 보장해야 한다는 점에 유의하세요.
보안 사고 시나리오와 대응
시나리오 1: 인포스틸러로 RT 대량 유출 의심
징후: 재사용 감지 이벤트가 평소의 수십 배로 급증
대응:
1. 감지된 패밀리는 자동 무효화되고 있음을 확인 (이미 방어 동작 중)
2. 영향 사용자 추출 → 강제 전체 세션 종료 + 비밀번호/passkey 재등록 안내
3. offline token 보유 사용자는 별도 점검 (로그아웃에도 살아남으므로)
4. AT 수명 임시 단축 (10분 → 5분) 검토
시나리오 2: 특정 사용자 계정 탈취 신고
# 1. 즉시 모든 세션 종료 (모든 디바이스에서 로그아웃)
kcadm.sh create users/USER-UUID/logout -r myrealm
# 2. offline 토큰 포함 동의(consent) 철회
kcadm.sh delete users/USER-UUID/consents/CLIENT-ID -r myrealm
# 3. 자격증명 재설정 요구 (비밀번호 + passkey 재등록)
kcadm.sh update users/USER-UUID -r myrealm \
-s 'requiredActions=["UPDATE_PASSWORD","webauthn-register-passkey"]'
AT는 차단할 수 없으므로(stateless), AT 수명만큼의 잔여 위험은 수용하거나, 고위험 API에 한해 introspection으로 세션 생존을 확인하게 합니다.
시나리오 3: IdP 서명 키 유출 의심
토큰 수명주기 설계가 빛나는 순간입니다. 키를 회전(구 키 즉시 제거)하면 구 키로 서명된 모든 AT가 한꺼번에 무효화됩니다. AT 수명이 10분이라면 "유출 키로 위조 가능한 창"도 키 제거 즉시 닫힙니다. RT는 서버 측 상태로 검증되므로 세션 무효화로 대응합니다.
모니터링 지표
| 지표 | 의미 | 경보 기준 예 |
|---|---|---|
| RT 재사용 감지 수 | 탈취 시도 or 클라이언트 버그 | 시간당 N건 초과 |
| 동일 패밀리 다국가 IP 사용 | 세션 하이재킹 | 1건이라도 |
| invalid_grant 비율 | 만료/오용/공격 혼합 신호 | 평시 대비 3배 |
| offline token 발급 수 | 장기 자격증명 증가 | 주간 추세 감시 |
| 세션당 평균 수명 | 정책 실효성 확인 | 분포 변화 |
안티패턴 모음
| 안티패턴 | 문제 | 교정 |
|---|---|---|
| AT 수명 24시간 | 차단 불가 토큰의 피해 창 24시간 | 5~15분 + RT 갱신 |
| rotation 없이 RT 90일 | 탈취 감지 수단 전무 | rotation + reuse detection |
| RT를 localStorage에 저장 | XSS 한 번에 장기 자격증명 유출 | HttpOnly 쿠키 또는 BFF |
| 로그아웃 시 쿠키만 삭제 | IdP 세션/RT 생존 → 자동 재로그인 | RP-Initiated Logout + revoke |
| 모든 클라이언트에 offline_access 허용 | 로그아웃 불가 토큰 남발 | scope를 필요 클라이언트로 제한 |
| 세션 저장소 없이 다중 인스턴스 IdP | 재사용 감지가 인스턴스별로 동작 | 공유 저장소/클러스터 캐시 |
| 탭마다 독립 RT 갱신 | rotation 오발 무효화 | 갱신 단일화 (lock 또는 BFF) |
마치며
탈취에 강한 토큰 수명주기 설계의 핵심을 요약합니다.
- AT는 짧게, 차단 불가를 전제로: 5~15분. 피해 창은 수명으로 통제합니다.
- RT는 stateful하게, 탈취를 전제로: rotation + reuse detection + 패밀리 무효화. 도둑과 주인을 구분할 필요 없이, 충돌 즉시 전부 끊습니다.
- 세션은 3계층으로 사고하세요: 앱 세션, IdP 세션(쿠키), SSO 세션(서버 상태)은 따로 만료됩니다. Keycloak에서 RT 수명은 세션 수명의 파생물이라는 점을 기억하세요.
- 로그아웃은 분산 트랜잭션입니다: RP-Initiated Logout + token revocation + Back-Channel Logout 전파까지가 한 세트입니다.
- SPA라면 BFF를 기본값으로: 토큰을 브라우저에서 치우면 rotation의 동시성 문제와 XSS 유출이 함께 사라집니다.
- 사고 대응 절차를 미리 연습하세요: 세션 강제 종료, consent 철회, 키 회전 명령을 런북으로 만들어 두면, 새벽 3시의 대응 속도가 달라집니다.
인증의 진짜 실력은 로그인 화면이 아니라 토큰이 만료되고, 회전하고, 폐기되는 그 보이지 않는 수명주기에서 드러납니다. 지금 운영 중인 시스템의 realm 설정을 열어, 각 타임아웃 값에 "왜?"를 물어보는 것부터 시작해 보시기 바랍니다.
참고 자료
- OAuth 2.1 draft (draft-ietf-oauth-v2-1)
- RFC 9700 - Best Current Practice for OAuth 2.0 Security
- RFC 6749 - The OAuth 2.0 Authorization Framework
- RFC 7009 - OAuth 2.0 Token Revocation
- RFC 7662 - OAuth 2.0 Token Introspection
- RFC 9449 - OAuth 2.0 Demonstrating Proof of Possession (DPoP)
- OpenID Connect Core 1.0
- OpenID Connect RP-Initiated Logout 1.0
- OpenID Connect Back-Channel Logout 1.0
- OpenID Connect Session Management 1.0
- Keycloak Documentation
- Keycloak Server Administration - Managing user sessions
- Keycloak 26.6.0 Release Notes