Refresh และ Logout
อายุของ token และ session
หัวข้อที่มีชื่อว่า “อายุของ token และ session”Keycloak จัดการแนวคิดสามอย่างที่เกี่ยวข้องกันซึ่งควบคุมระยะเวลาที่ผู้ใช้ยังคง login อยู่:
| แนวคิด | ค่าเริ่มต้นทั่วไป | ควบคุมอะไร |
|---|---|---|
| Access token lifespan | 5 นาที | ระยะเวลาที่ JWT มีผลก่อน backend จะปฏิเสธ |
| Refresh token lifespan | 30 นาที (SSO Session Idle) | ระยะเวลาที่ refresh token สามารถใช้รับ access token ใหม่ |
| SSO session max | 10 ชั่วโมง | ระยะเวลา session สูงสุดโดยสมบูรณ์ แม้มีการ refresh อยู่ |
เมื่อ access token หมดอายุ frontend ควรใช้ refresh token เพื่อรับ token ใหม่แบบ silent โดยไม่บังคับให้ผู้ใช้ login ใหม่ เมื่อ SSO session หมดอายุ ผู้ใช้ต้อง authenticate ใหม่
การ refresh token ด้วย updateToken
หัวข้อที่มีชื่อว่า “การ refresh token ด้วย updateToken”keycloak.updateToken(minValidity) คือวิธีที่เหมาะสมในการจัดการ refresh ใน keycloak-js เรียกใช้ก่อน API request ใดก็ตาม ถ้า access token ปัจจุบันจะหมดอายุภายใน minValidity วินาที keycloak-js จะแลก refresh token เพื่อรับ access token ใหม่แบบ silent:
// Refresh the token if it expires within 60 seconds,
// then call the API with the fresh token.
async function callApi(path) {
try {
await keycloak.updateToken(60);
} catch {
// Refresh token has expired — force re-login.
keycloak.login();
return;
}
const response = await fetch(`https://api.example.com${path}`, {
headers: { Authorization: `Bearer ${keycloak.token}` },
});
return response.json();
}ถ้า updateToken reject (refresh token หมดอายุหรือถูกเพิกถอน) แสดงว่า session ของผู้ใช้หมดแล้ว ควร redirect ไปยัง login ด้วย keycloak.login()
การ logout อย่างถูกต้อง
หัวข้อที่มีชื่อว่า “การ logout อย่างถูกต้อง”การเรียกฟังก์ชัน “clear state” ในแอปของคุณเพียงอย่างเดียวไม่เพียงพอ SSO session ของผู้ใช้ยังคงอยู่ใน Keycloak ซึ่งหมายความว่าพวกเขาสามารถเข้าถึงแอปอื่น ๆ ใน realm เดียวกันได้ทันทีโดยไม่ต้อง authenticate ใหม่
การ logout ที่ถูกต้องต้องกดไปที่ end-session endpoint ของ Keycloak keycloak-js ทำสิ่งนี้ให้คุณ:
// Redirect to Keycloak's end-session endpoint,
// then back to your app's home page.
keycloak.logout({ redirectUri: 'https://app.example.com/' });ภายใต้ hood นี้จะ redirect browser ไปที่:
/realms/{realm}/protocol/openid-connect/logout ?id_token_hint=<id_token> &post_logout_redirect_uri=https://app.example.com/Keycloak จะล้าง SSO session cookie, ทำเครื่องหมาย refresh token ว่าถูกเพิกถอน และ redirect กลับมายังแอปของคุณ
สิ่งที่ถูกล้าง
หัวข้อที่มีชื่อว่า “สิ่งที่ถูกล้าง”| การกระทำ | ล้าง token ในเครื่อง | ล้าง Keycloak session |
|---|---|---|
| Reset state ในแอปเท่านั้น | ใช่ | ไม่ |
keycloak.logout() | ใช่ | ใช่ |
ข้อแลกเปลี่ยน
หัวข้อที่มีชื่อว่า “ข้อแลกเปลี่ยน”| ตัวเลือก | Benefit | Cost |
|---|---|---|
| Silent refresh ผ่าน updateToken() | ผู้ใช้ไม่รู้สึกถูก interrupt session ต่อเนื่องได้นานตราบใดที่ refresh token ยังไม่หมดอายุ | ต้องเขียน error handling ให้ครบ เพราะถ้า refresh ล้มเหลวแบบเงียบ ๆ แอปอาจค้างอยู่ในสถานะที่ดูเหมือน login แต่ยิง API ไม่ได้ |
| บังคับ re-login ทันทีเมื่อ access token หมดอายุ | Implementation ง่ายกว่า ไม่ต้องจัดการ refresh flow ที่ซับซ้อน | UX แย่ลงมาก เพราะผู้ใช้ต้องกรอกรหัสผ่านซ้ำบ่อย ทั้งที่ SSO session จริง ๆ ยังไม่หมดอายุ |
| ตั้งค่า SSO Session Idle/Max ให้สั้น | ลด window ความเสี่ยงหาก token หรือ session หลุด | ผู้ใช้ต้อง authenticate ใหม่บ่อยขึ้น กระทบ UX โดยเฉพาะแอปที่ใช้งานต่อเนื่องนาน ๆ |
ข้อผิดพลาดที่พบบ่อย
หัวข้อที่มีชื่อว่า “ข้อผิดพลาดที่พบบ่อย”- ไม่ handle กรณี updateToken() reject — ถ้า refresh token หมดอายุหรือถูกเพิกถอนแล้วแอปไม่ catch error ผู้ใช้จะเห็น API request ล้มเหลวเรื่อย ๆ โดยไม่รู้สาเหตุ ต้อง catch แล้วเรียก keycloak.login() เพื่อ redirect กลับไป authenticate ใหม่เสมอ
- Logout แค่ clear local state โดยไม่เรียก end-session endpoint — ลบ token ออกจากหน่วยความจำอย่างเดียวไม่ได้ล้าง SSO session cookie ของ Keycloak ทำให้ผู้ใช้ “logout” จากแอปแต่ยัง login อยู่ทั่ว realm
- Retry refresh แบบไม่มีที่สิ้นสุดเมื่อ network ล้มเหลวชั่วคราว — การไม่แยกระหว่าง network error กับ refresh token ที่หมดอายุจริง อาจทำให้แอป loop เรียก updateToken() รัว ๆ โดยไม่เคย fallback ไปหน้า login เลย
💡 ตัวอย่างจากของจริง
keycloak-js updateToken pattern — แอป production จำนวนมากเรียก updateToken(minValidity) แบบ silent ก่อนทุก API call ตามที่บทเรียนนี้แสดง และ catch การ reject เพื่อ redirect เข้า login เมื่อ refresh token หมดอายุจริง แทนที่จะปล่อยให้ request ล้มเหลวแบบเงียบ ๆ
Google Workspace / Gmail web — ใช้แนวคิดเดียวกันคือ session อายุยาวที่ refresh อัตโนมัติเบื้องหลัง แต่มี absolute session timeout (คล้าย SSO session max ของ Keycloak) บังคับให้ authenticate ใหม่เป็นระยะแม้ refresh จะยัง “สำเร็จ” อยู่ก็ตาม