diff --git a/auth.js b/auth.js index 5741d06..97a4556 100644 --- a/auth.js +++ b/auth.js @@ -16,6 +16,8 @@ const msalConfig = { const loginRequest = { scopes: ['User.Read'] }; +const API_BASE = '/loreal-sla-calculator/api'; + let msalInstance = null; let currentAccessToken = null; // In-memory only — never persisted let pendingResetToken = null; // ?reset_token= from URL @@ -55,7 +57,6 @@ async function initAuth() { const msalResponse = await msalInstance.handleRedirectPromise(); if (msalResponse && msalResponse.idToken) { - // Got a fresh MSAL token — exchange it for an app JWT await exchangeMsalToken(msalResponse.idToken); return; } @@ -75,7 +76,7 @@ async function initAuth() { async function tryRefresh() { try { - const res = await fetch('/api/auth/refresh', { method: 'POST', credentials: 'include' }); + const res = await fetch(`${API_BASE}/auth/refresh`, { method: 'POST', credentials: 'include' }); if (!res.ok) return false; const data = await res.json(); currentAccessToken = data.accessToken; @@ -94,22 +95,27 @@ setInterval(async () => { // ── SSO path ────────────────────────────────────────────────────────────────── async function authSsoLogin() { - if (!msalInstance) { - msalInstance = new msal.PublicClientApplication(msalConfig); - } - // Try silent SSO first; if it fails, do a full redirect try { - const silent = await msalInstance.ssoSilent(loginRequest); - await exchangeMsalToken(silent.idToken); - } catch { - await msalInstance.loginRedirect(loginRequest); + if (!msalInstance) { + msalInstance = new msal.PublicClientApplication(msalConfig); + } + // Try silent SSO first; if it fails, do a full redirect + try { + const silent = await msalInstance.ssoSilent(loginRequest); + await exchangeMsalToken(silent.idToken); + } catch { + await msalInstance.loginRedirect(loginRequest); + } + } catch (e) { + console.error('SSO login error:', e); + showAuthView('choice'); } } async function exchangeMsalToken(idToken) { showAuthView('loading'); try { - const res = await fetch('/api/auth/sso', { + const res = await fetch(`${API_BASE}/auth/sso`, { method: 'POST', credentials: 'include', headers: { 'Content-Type': 'application/json' }, @@ -139,7 +145,7 @@ async function authEmailLogin(event) { btn.textContent = 'Signing in…'; try { - const res = await fetch('/api/auth/login', { + const res = await fetch(`${API_BASE}/auth/login`, { method: 'POST', credentials: 'include', headers: { 'Content-Type': 'application/json' }, @@ -180,7 +186,7 @@ async function authRegister(event) { btn.textContent = 'Creating account…'; try { - const res = await fetch('/api/auth/register', { + const res = await fetch(`${API_BASE}/auth/register`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email, password }), @@ -211,7 +217,7 @@ async function authForgotPassword(event) { msgEl.className = 'hidden mb-4 p-3 text-sm rounded-lg'; try { - await fetch('/api/auth/forgot-password', { + await fetch(`${API_BASE}/auth/forgot-password`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email }), @@ -232,7 +238,7 @@ async function authForgotPassword(event) { async function handleResetTokenParam(token) { showAuthView('loading'); try { - const res = await fetch(`/api/auth/validate-reset-token/${token}`); + const res = await fetch(`${API_BASE}/auth/validate-reset-token/${token}`); const data = await res.json(); if (!res.ok || !data.valid) { showAuthView('login'); @@ -264,7 +270,7 @@ async function authResetPassword(event) { btn.textContent = 'Saving…'; try { - const res = await fetch('/api/auth/reset-password', { + const res = await fetch(`${API_BASE}/auth/reset-password`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ token: pendingResetToken, password }), @@ -287,10 +293,9 @@ async function authResetPassword(event) { async function handleVerifyEmail(token) { showAuthView('loading'); try { - const res = await fetch(`/api/auth/verify-email/${token}`); + const res = await fetch(`${API_BASE}/auth/verify-email/${token}`); const data = await res.json(); if (res.ok) { - // Show login with a success pre-fill message const errEl = document.getElementById('authLoginError'); if (errEl) { errEl.textContent = 'Email verified! You can now sign in.'; @@ -308,13 +313,13 @@ async function handleVerifyEmail(token) { async function authResendVerification() { if (!pendingVerifyEmail) return; try { - await fetch('/api/auth/register', { + await fetch(`${API_BASE}/auth/register`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email: pendingVerifyEmail, _resend: true }), }); } catch { - // Silently ignore — user sees no feedback change + // Silently ignore } } @@ -336,14 +341,13 @@ function onAuthSuccess(user) { async function signOut() { try { - await fetch('/api/auth/logout', { method: 'POST', credentials: 'include' }); + await fetch(`${API_BASE}/auth/logout`, { method: 'POST', credentials: 'include' }); } catch { // Ignore network errors on logout } currentAccessToken = null; - // Also clear MSAL session if it was used if (msalInstance) { try { await msalInstance.logoutSilent(); @@ -352,7 +356,6 @@ async function signOut() { } } - // Show auth overlay again const overlay = document.getElementById('authOverlay'); if (overlay) overlay.style.display = ''; diff --git a/script.js b/script.js index ec7ea1d..a5dbefa 100644 --- a/script.js +++ b/script.js @@ -8,7 +8,8 @@ let CONFIG = null; // ── API fetch helper ────────────────────────────────────────────────────────── // Automatically includes the in-memory access token as a Bearer header. // On 401, attempts one silent token refresh before giving up. -async function apiFetch(url, options = {}) { +async function apiFetch(path, options = {}) { + const url = `/loreal-sla-calculator/api${path}`; const headers = { ...(options.headers || {}) }; if (currentAccessToken) headers['Authorization'] = `Bearer ${currentAccessToken}`;