ข้ามไปยังเนื้อหา

Refresh และ Logout

Keycloak จัดการแนวคิดสามอย่างที่เกี่ยวข้องกันซึ่งควบคุมระยะเวลาที่ผู้ใช้ยังคง login อยู่:

แนวคิดค่าเริ่มต้นทั่วไปควบคุมอะไร
Access token lifespan5 นาทีระยะเวลาที่ JWT มีผลก่อน backend จะปฏิเสธ
Refresh token lifespan30 นาที (SSO Session Idle)ระยะเวลาที่ refresh token สามารถใช้รับ access token ใหม่
SSO session max10 ชั่วโมงระยะเวลา session สูงสุดโดยสมบูรณ์ แม้มีการ refresh อยู่

เมื่อ access token หมดอายุ frontend ควรใช้ refresh token เพื่อรับ token ใหม่แบบ silent โดยไม่บังคับให้ผู้ใช้ login ใหม่ เมื่อ SSO session หมดอายุ ผู้ใช้ต้อง authenticate ใหม่

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()

การเรียกฟังก์ชัน “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()ใช่ใช่
ตัวเลือกBenefitCost
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 จะยัง “สำเร็จ” อยู่ก็ตาม

keycloak.updateToken(60) ทำหน้าที่อะไร?
แอปของคุณควรทำอย่างไรเมื่อ keycloak.updateToken() reject (throw)?
เหตุใดการล้าง state ของแอปในเครื่องเพียงอย่างเดียวจึงไม่เพียงพอสำหรับการ logout?
SSO Session Idle timeout ควบคุมอะไร?