690320:2012 login #01
Build and Deploy / deploy (push) Successful in 6m43s

This commit is contained in:
2026-03-20 20:12:03 +07:00
parent dcf55f4d08
commit bac263c097
+28 -25
View File
@@ -11,15 +11,19 @@ const loginSchema = z.object({
password: z.string().min(1), password: z.string().min(1),
}); });
const baseUrl = (typeof window === "undefined" ? process.env.INTERNAL_API_URL : null) || process.env.NEXT_PUBLIC_API_URL || "http://localhost:3001/api"; // ✅ ใช้แบบ SSR-safe (ดีที่สุด)
const baseUrl =
(typeof window === "undefined" ? process.env.INTERNAL_API_URL : null) ||
process.env.NEXT_PUBLIC_API_URL ||
"http://localhost:3001/api";
// Helper to parse JWT expiry // Helper to parse JWT expiry
function getJwtExpiry(token: string): number { function getJwtExpiry(token: string): number {
try { try {
const payload = JSON.parse(atob(token.split('.')[1])); const payload = JSON.parse(atob(token.split(".")[1]));
return payload.exp * 1000; // Convert to ms return payload.exp * 1000;
} catch { } catch {
return Date.now(); // If invalid, treat as expired return Date.now();
} }
} }
@@ -46,9 +50,7 @@ async function refreshAccessToken(token: JWT) {
accessTokenExpires: getJwtExpiry(data.access_token), accessTokenExpires: getJwtExpiry(data.access_token),
refreshToken: data.refresh_token ?? token.refreshToken, refreshToken: data.refresh_token ?? token.refreshToken,
}; };
} catch (error) { } catch {
// RefreshAccessTokenError - token will be invalidated
return { return {
...token, ...token,
error: "RefreshAccessTokenError", error: "RefreshAccessTokenError",
@@ -73,15 +75,15 @@ export const {
if (!credentials?.username || !credentials?.password) return null; if (!credentials?.username || !credentials?.password) return null;
try { try {
// 1. Sanitize payload (Only send username and password) // ✅ sanitize payload
const payload = { const payload = {
username: credentials.username as string, username: credentials.username as string,
password: credentials.password as string, password: credentials.password as string,
}; };
console.log(`[AUTH] Attempting login at: ${baseUrl}/auth/login`); console.log(`[AUTH] Attempting login at: ${baseUrl}/auth/login`);
console.log(`[AUTH] Current process.env.INTERNAL_API_URL: ${process.env.INTERNAL_API_URL}`); console.log(`[AUTH] INTERNAL_API_URL: ${process.env.INTERNAL_API_URL}`);
console.log(`[AUTH] Current process.env.NEXT_PUBLIC_API_URL: ${process.env.NEXT_PUBLIC_API_URL}`); console.log(`[AUTH] NEXT_PUBLIC_API_URL: ${process.env.NEXT_PUBLIC_API_URL}`);
const res = await fetch(`${baseUrl}/auth/login`, { const res = await fetch(`${baseUrl}/auth/login`, {
method: "POST", method: "POST",
@@ -89,7 +91,7 @@ export const {
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
}, },
cache: 'no-store', // Disable caching for auth requests cache: "no-store",
}); });
if (!res.ok) { if (!res.ok) {
@@ -99,16 +101,21 @@ export const {
return null; return null;
} }
const data = await res.json(); const responseJson = await res.json();
// Handling both { data: { ... } } and direct { ... } response formats console.log("[AUTH] Backend raw response:", JSON.stringify(responseJson));
const backendData = data.data || data;
const backendData = responseJson.data || responseJson;
if (!backendData || !backendData.access_token) { if (!backendData || !backendData.access_token) {
console.error("[AUTH] Login failed: Invalid response format from backend (missing access_token)"); console.error("[AUTH] Invalid backend response:", backendData);
return null; return null;
} }
console.log(`[AUTH] Login Successful for user: ${backendData.user?.username || 'unknown'}`); console.log(
`[AUTH] Login Successful for user: ${
backendData.user?.username || "unknown"
}`
);
return { return {
id: backendData.user.user_id.toString(), id: backendData.user.user_id.toString(),
@@ -120,9 +127,8 @@ export const {
accessToken: backendData.access_token, accessToken: backendData.access_token,
refreshToken: backendData.refresh_token, refreshToken: backendData.refresh_token,
} as User; } as User;
} catch (error) { } catch (error) {
console.error("[AUTH] Network/Fetch Error during authorize:", error); console.error("[AUTH] Network Error:", error);
return null; return null;
} }
}, },
@@ -138,7 +144,7 @@ export const {
return { return {
...token, ...token,
id: user.id, id: user.id,
username: user.username, // ✅ Save username username: user.username,
role: user.role, role: user.role,
organizationId: user.organizationId, organizationId: user.organizationId,
accessToken: user.accessToken, accessToken: user.accessToken,
@@ -147,23 +153,20 @@ export const {
}; };
} }
// Return previous token if valid (minus 10s buffer)
if (Date.now() < (token.accessTokenExpires as number) - 10000) { if (Date.now() < (token.accessTokenExpires as number) - 10000) {
return token; return token;
} }
// If existing token has an error, do not retry refresh (prevents infinite loop)
if (token.error) { if (token.error) {
return token; return token;
} }
// Token expired, refresh it
return refreshAccessToken(token); return refreshAccessToken(token);
}, },
async session({ session, token }) { async session({ session, token }) {
if (token && session.user) { if (token && session.user) {
session.user.id = token.id as string; session.user.id = token.id as string;
session.user.username = token.username as string; // ✅ Restore username session.user.username = token.username as string;
session.user.role = token.role as string; session.user.role = token.role as string;
session.user.organizationId = token.organizationId as number; session.user.organizationId = token.organizationId as number;
@@ -176,8 +179,8 @@ export const {
}, },
session: { session: {
strategy: "jwt", strategy: "jwt",
maxAge: 24 * 60 * 60, // 24 hours maxAge: 24 * 60 * 60,
}, },
secret: process.env.AUTH_SECRET, secret: process.env.AUTH_SECRET,
debug: process.env.NODE_ENV === "development", debug: process.env.NODE_ENV === "development",
}); });