Fix API base path: use /loreal-sla-calculator/api prefix for all fetch calls
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
e54222190b
commit
7ba7cebf56
2 changed files with 28 additions and 24 deletions
49
auth.js
49
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 = '';
|
||||
|
||||
|
|
|
|||
|
|
@ -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}`;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue