52 lines
1.2 KiB
JavaScript
52 lines
1.2 KiB
JavaScript
|
|
import { API_URL } from "@/config";
|
|||
|
|
|
|||
|
|
|
|||
|
|
// Auth fetch wrapper
|
|||
|
|
export const authFetch = async (url, options = {}, retry = true) => {
|
|||
|
|
const res = await fetch(url, {
|
|||
|
|
...options,
|
|||
|
|
credentials: "include", // cookie goes automatically
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
if (res.status === 401 && retry) {
|
|||
|
|
// attempt refresh
|
|||
|
|
try {
|
|||
|
|
const refreshRes = await fetch(`${API_URL}/refresh`, {
|
|||
|
|
method: "POST",
|
|||
|
|
credentials: "include",
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
if (!refreshRes.ok) throw new Error("Refresh failed");
|
|||
|
|
|
|||
|
|
// Retry original request once after refresh
|
|||
|
|
return authFetch(url, options, false);
|
|||
|
|
} catch (err) {
|
|||
|
|
console.error("Refresh token failed:", err);
|
|||
|
|
return res;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return res;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// Refresh token function (HttpOnly cookie flow)
|
|||
|
|
export async function refreshAccessToken() {
|
|||
|
|
try {
|
|||
|
|
const res = await fetch(`${API_URL}/refresh`, {
|
|||
|
|
method: "POST",
|
|||
|
|
credentials: "include", // send HttpOnly cookies
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
if (!res.ok) {
|
|||
|
|
throw new Error("Failed to refresh token");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Typically the server just updates the cookie
|
|||
|
|
// It may return a new access token too, but we don’t store it client-side.
|
|||
|
|
return true;
|
|||
|
|
} catch (err) {
|
|||
|
|
console.error("Refresh token failed:", err);
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
}
|