diff --git a/web/src/components/LoginForm.jsx b/web/src/components/LoginForm.jsx
index f8fa111..6119ad2 100644
--- a/web/src/components/LoginForm.jsx
+++ b/web/src/components/LoginForm.jsx
@@ -102,7 +102,7 @@ export default function LoginForm() {
{/* Checkbox และ Link ลืมรหัสผ่าน */}
diff --git a/web/src/services/authApi.js b/web/src/services/authApi.js
index 7699627..eae8985 100644
--- a/web/src/services/authApi.js
+++ b/web/src/services/authApi.js
@@ -15,8 +15,18 @@ const API_BASE_URL = import.meta.env.VITE_API_BASE_URL;
* แปลง Object ให้เป็นฟอร์มข้อมูล (x-www-form-urlencoded)
*/
const toFormUrlEncoded = (data) => {
+ // วนซ้ำ key และ encode
return Object.keys(data)
- .map(key => encodeURIComponent(key) + '=' + encodeURIComponent(data[key]))
+ .map(key => {
+ let value = data[key];
+ // รับค่า remember_me (boolean) มาแปลงเป็น String 'true'
+ if (value === true) {
+ value = 'true';
+ } else if (value === false) {
+ value = 'false'; // หรือจะส่งเฉพาะเมื่อเป็น true ก็ได้
+ }
+ return encodeURIComponent(key) + '=' + encodeURIComponent(value);
+ })
.join('&');
};
@@ -121,6 +131,8 @@ export const useLoginMutation = () => {
// 1. จัดการ Token และ User Data
localStorage.setItem('token', data.access_token);
+ // บันทึก Refresh Token แยกต่างหาก
+ localStorage.setItem('refresh_token', data.refresh_token);
localStorage.setItem('user', JSON.stringify(data.user));
localStorage.setItem('role', data.role); // บันทึก Role ที่ถูกต้อง
@@ -250,4 +262,22 @@ export const useConfirmPasswordReset = () => {
throw new Error(msg);
},
});
+};
+
+/**
+ * ฟังก์ชันสำหรับเรียก API เพื่อต่ออายุ Access Token ด้วย Refresh Token
+ */
+export const refreshAccessToken = async () => {
+ const refresh = localStorage.getItem('refresh_token'); // เก็บ Refresh Token แยกต่างหาก
+
+ if (!refresh) {
+ throw new Error("Refresh token not found.");
+ }
+
+ const response = await axios.post(`${API_BASE_URL}/api/v1/auth/jwt/refresh/`, {
+ refresh: refresh,
+ });
+
+ // คืนค่า Access Token ใหม่
+ return response.data.access;
};
\ No newline at end of file
diff --git a/web/src/services/axiosClient.js b/web/src/services/axiosClient.js
index 6612219..907552d 100644
--- a/web/src/services/axiosClient.js
+++ b/web/src/services/axiosClient.js
@@ -1,6 +1,7 @@
import axios from 'axios';
import { getStore } from '../app/store';
import { logout } from '../features/auth/authSlice';
+import { refreshAccessToken } from './authApi';
// REGEX ตรวจจับตัวเลขที่ใหญ่เกิน 15 หลัก (ซึ่งเกินขีดจำกัดความปลอดภัยของ JS)
const bigIntRegex = /"id":(\d{15,})/g;
@@ -55,8 +56,37 @@ axiosClient.interceptors.request.use(
axiosClient.interceptors.response.use(
(response) => response,
- (error) => {
+ async (error) => {
const status = error.response ? error.response.status : null;
+ const originalRequest = error.config;
+
+ // ถ้าเป็น 401 และ Request นั้นยังไม่ถูกลอง Refresh
+ if (status === 401 && !originalRequest._retry) {
+
+ originalRequest._retry = true; // ตั้ง Flag ว่ากำลังจะลอง Refresh
+
+ const storeInstance = getStore();
+
+ try {
+ // 1. เรียกฟังก์ชัน Refresh Token
+ const newAccessToken = await refreshAccessToken();
+
+ // 2. บันทึก Access Token ใหม่
+ localStorage.setItem('token', newAccessToken);
+
+ // 3. อัปเดต Header ของ Request เดิม
+ originalRequest.headers.Authorization = `Bearer ${newAccessToken}`;
+
+ // 4. ลองเรียก Request เดิมซ้ำอีกครั้ง
+ return axiosClient(originalRequest);
+
+ } catch (refreshError) {
+ // หาก Refresh Token ล้มเหลว (หมดอายุ 30 วันแล้ว)
+ console.error("JWT Refresh Failed. Logging out.", refreshError);
+ storeInstance.dispatch(logout()); // บังคับ Logout
+ return Promise.reject(error);
+ }
+ }
// ถ้าได้รับ 401 หรือ 403 (Token หมดอายุ/ไม่มีสิทธิ์)
if (status === 401 || status === 403) {