SSO, logout và session

4 câu hỏi~25 phútTừ khóa: SSO session, KEYCLOAK_IDENTITY cookie, refresh token, offline_access, RP-initiated logout, back-channel logout, revocation

Tiếp đi: SSO và logout trong Keycloak chạy thế nào?

Khái niệm SSO đã có ở 4.4.7. Bài này đi vào cơ chế session của Keycloak và cách logout đúng.

1. Bài toán

2. Vấn đề

3. Giải pháp: ba tầng thời gian

ThứNằm ở đâuSống bao lâu
SSO sessionServer Keycloak + cookie KEYCLOAK_IDENTITY/KEYCLOAK_SESSION trên domain KeycloakSSO Session Idle / Max
Refresh tokenClient; gắn với SSO sessionHết khi session idle/max hết hoặc logout
Access tokenClient, gửi kèm requestAccess Token Lifespan (vài phút), không thu hồi được khi verify offline
Offline tokenClient (scope offline_access)Offline Session Idle (mặc định 30 ngày), sống cả khi SSO session hết

4. Code từng bước

Bước 1: Cấu hình (Realm settings → Sessions / Tokens)

SSO Session Idle: 30m          SSO Session Max: 10h
Offline Session Idle: 30d      Offline Session Max Limited: On, 90d
Revoke Refresh Token: On       (rotation: mỗi refresh token chỉ dùng 1 lần)

Bước 2: Refresh và offline token

KC=http://localhost:8080/realms/shop/protocol/openid-connect
# refresh
curl -s -X POST $KC/token -d grant_type=refresh_token \
  -d client_id=shop-web -d refresh_token="$REFRESH_TOKEN"

# mobile xin offline token: thêm scope offline_access khi login
#   .../auth?...&scope=openid%20offline_access
# user cần role offline_access (mặc định có trong default-roles-shop)

Bước 3: RP-initiated logout (SPA chuyển trình duyệt tới Keycloak):

GET $KC/logout?id_token_hint=$ID_TOKEN
              &post_logout_redirect_uri=https://shop.example.com/
              &client_id=shop-web

URI phải nằm trong "Valid post logout redirect URIs". Keycloak 18+ yêu cầu id_token_hint hoặc client_id thay cho tham số redirect_uri cũ.

Bước 4: Back-channel logout cho shop-admin (có backend giữ session riêng):

Clients → shop-admin → Settings → Logout settings
   Backchannel logout URL: https://admin.shop.example.com/logout/connect/back-channel/keycloak
   Backchannel logout session required: On

Spring Security 6.2+ có sẵn .oidcLogout(l -> l.backChannel(Customizer.withDefaults())) để nhận logout token và hủy HTTP session.

Khóa bob ngay (admin):

kcadm.sh update users/$BOB_ID -r shop -s enabled=false
kcadm.sh create users/$BOB_ID/logout -r shop    # hủy mọi session, kể cả offline

5. Cách hoạt động

SSO
shop-web ──/auth──> Keycloak: chưa có cookie → form login → tạo SSO session + cookie
shop-admin ──/auth──> Keycloak: có cookie hợp lệ → không hỏi password → code ngay
(mỗi client nhận token riêng, aud/role riêng; chung SSO session)

Logout từ shop-admin
browser ──/logout──> Keycloak: xóa SSO session + cookie
                        ├─ back-channel POST logout_token ──> shop-admin backend (hủy HTTP session)
                        └─ (front-channel, nếu bật) iframe tới shop-web
shop-web: refresh token lần sau → 400 invalid_grant → về trang login
Access token đang lưu hành: VẪN hợp lệ tới exp ở order-service

6. So sánh cách logout

CáchAi gọiTin cậy
Chỉ xóa token ở clientAppKhông phải logout thật
RP-initiatedBrowser → KeycloakHủy SSO session
Front-channelBrowser (iframe) → các appDễ hỏng do chặn cookie bên thứ ba
Back-channelKeycloak → backend app (server-to-server)Tin cậy nhất, cần app có backend

7. Khi nào nên dùng / không nên dùng

Bob đã logout, nhưng ai đó copy được access token của bob vẫn gọi order-service thành công. Vậy logout có tác dụng gì?

Bạn quan sát đúng. Logout hủy session và refresh token, không làm JWT đã ký "biến mất". order-service verify chữ ký offline nên không biết session đã hết.

Cách giảm rủi roĐánh đổi
Access token 5 phútCửa sổ rủi ro tối đa 5 phút
Token introspection (/token/introspect) cho API nhạy cảmMỗi request gọi Keycloak, thêm độ trễ
Nhận back-channel logout ở gateway, giữ deny-list sid trong Redis tới expThêm hạ tầng
Sender-constrained token (DPoP, mTLS)Token copy không dùng được nếu thiếu key; client phức tạp hơn

Phần lớn hệ thống chọn: token ngắn + introspection cho vài endpoint quan trọng.

Restart Keycloak thì user có bị đá ra hết không? Session lưu ở đâu?

Phụ thuộc phiên bản. Từ Keycloak 25, tính năng persistent user sessions bật mặc định: session được lưu xuống database, cache Infinispan chỉ giữ phần đang dùng. Restart hoặc rolling upgrade, user vẫn còn đăng nhập. Bản cũ hơn giữ online session chỉ trong Infinispan: restart tất cả node là mất (offline session thì vẫn ở DB).

Clustering và cache xem bài 12.6.

Phỏng vấn hỏi SSO session, refresh token và logout trong Keycloak thì trả lời sao?

Q1. SSO trong Keycloak hoạt động thế nào?

🇻🇳 Tiếng Việt:

Lần đầu login, Keycloak tạo SSO session và đặt cookie trên domain của nó. App khác trong cùng realm redirect sang thì Keycloak thấy cookie, phát code ngay không hỏi password. Mỗi app vẫn nhận token riêng.

🇬🇧 English:

On first login Keycloak creates an SSO session and sets a cookie on its own domain. When another client in the same realm redirects there, Keycloak sees the cookie and issues a code without asking for the password. Each application still gets its own tokens.

Q2. Access token, refresh token, offline token khác nhau?

🇻🇳 Tiếng Việt:

Access token ngắn, gửi tới API. Refresh token gắn với SSO session, dùng xin access token mới, chết khi session hết. Offline token xin bằng scope offline_access, sống độc lập với SSO session, hợp cho mobile hoặc job, phải lưu an toàn.

🇬🇧 English:

The access token is short-lived and sent to APIs. The refresh token is bound to the SSO session and gets new access tokens until the session ends. An offline token, requested with offline_access, survives the SSO session, suits mobile apps or jobs, and must be stored securely.

Q3. Logout xong access token cũ có còn dùng được không?

🇻🇳 Tiếng Việt:

Còn, tới khi hết hạn, vì service verify JWT offline. Logout hủy session và refresh token. Em giảm rủi ro bằng token ngắn, back-channel logout, và introspection cho API nhạy cảm.

🇬🇧 English:

Yes, until it expires, because services verify the JWT offline. Logout kills the session and refresh tokens. I reduce the risk with short-lived tokens, back-channel logout and introspection for sensitive APIs.

Cách nhớ ngắn gọn


Tự kiểm tra

Chỉ xóa token trong localStorage có phải logout không?

Không. SSO session và cookie trên Keycloak còn, login lại không cần password.

Tham số nào cần cho RP-initiated logout ở Keycloak 26?

id_token_hint (hoặc client_id) và post_logout_redirect_uri đã đăng ký.

Back-channel logout khác front-channel thế nào?

Keycloak gọi server-to-server tới backend app với logout token, không phụ thuộc cookie trình duyệt.

Revoke Refresh Token bật để làm gì?

Rotation: refresh token chỉ dùng một lần; dùng lại token cũ bị từ chối, phát hiện token bị đánh cắp.