fixed request for reauth on clicking show folder

This commit is contained in:
2026-01-10 19:39:57 +00:00
parent c22ada9c7e
commit 221e9d1f53
4 changed files with 44 additions and 35 deletions
+5 -8
View File
@@ -34,9 +34,9 @@ const getGraphToken = (c?: any) => {
const headerToken = c?.req?.header ? c.req.header('x-graph-token') : ''; const headerToken = c?.req?.header ? c.req.header('x-graph-token') : '';
const envToken = process.env.GRAPH_TOKEN || process.env.MS_GRAPH_TOKEN || ''; const envToken = process.env.GRAPH_TOKEN || process.env.MS_GRAPH_TOKEN || '';
const token = headerToken || envToken; const token = headerToken || envToken;
console.log('[getGraphToken] Header token:', headerToken ? headerToken.substring(0, 20) + '...' : 'NONE'); if (!headerToken && !envToken) {
console.log('[getGraphToken] Env token:', envToken ? 'SET' : 'NOT SET'); console.warn('[getGraphToken] No token available in header or environment');
console.log('[getGraphToken] Using:', token ? token.substring(0, 20) + '...' : 'NONE'); }
return token; return token;
}; };
@@ -120,18 +120,15 @@ const filterByCategory = (items: DriveItem[], category?: string) => {
// List/search job files via Graph using a shared folder link // List/search job files via Graph using a shared folder link
app.get('/api/job-files', async (c) => { app.get('/api/job-files', async (c) => {
try { try {
console.log('[job-files] Request received');
const token = getGraphToken(c); const token = getGraphToken(c);
if (!token) { if (!token) {
console.log('[job-files] No token found'); console.error('[job-files] No Graph token available (not in header or env)');
return c.json({ error: 'GRAPH_TOKEN missing' }, 500); return c.json({ error: 'Graph access token required. Please sign in again.' }, 401);
} }
console.log('[job-files] Token found:', token.substring(0, 20) + '...');
const link = c.req.query('link'); const link = c.req.query('link');
const q = c.req.query('q') || ''; const q = c.req.query('q') || '';
const category = c.req.query('category') || ''; const category = c.req.query('category') || '';
if (!link) return c.json({ error: 'link required' }, 400); if (!link) return c.json({ error: 'link required' }, 400);
console.log('[job-files] Link:', link);
const { driveId, itemId } = await resolveShareLink(link, token); const { driveId, itemId } = await resolveShareLink(link, token);
+4 -3
View File
@@ -880,7 +880,6 @@
const iframeViewerModal = document.getElementById('iframeViewerModal'); const iframeViewerModal = document.getElementById('iframeViewerModal');
const iframeViewer = document.getElementById('iframeViewer'); const iframeViewer = document.getElementById('iframeViewer');
const iframeLoader = document.getElementById('iframeLoader'); const iframeLoader = document.getElementById('iframeLoader');
iframeLoader.style.display = 'none'; // disable loader overlay entirely
const iframeTitle = document.getElementById('iframeTitle'); const iframeTitle = document.getElementById('iframeTitle');
const iframeBackBtn = document.getElementById('iframeBackBtn'); const iframeBackBtn = document.getElementById('iframeBackBtn');
const iframeCloseBtn = document.getElementById('iframeCloseBtn'); const iframeCloseBtn = document.getElementById('iframeCloseBtn');
@@ -1354,12 +1353,14 @@
iframeTitle.textContent = job.Job_Number ? `Job# ${job.Job_Number}` : 'Job Files'; iframeTitle.textContent = job.Job_Number ? `Job# ${job.Job_Number}` : 'Job Files';
fileListContainer.classList.remove('hidden'); fileListContainer.classList.remove('hidden');
iframeViewer.classList.add('hidden'); iframeViewer.classList.add('hidden');
pdfViewer.classList.add('hidden');
// Check if we have cached files // Check if we have cached files
const cached = fileCache.get(link); const cached = fileCache.get(link);
if (cached) { if (cached) {
console.log('Using cached files for job', job.Job_Number); console.log('Using cached files for job', job.Job_Number);
fileListState.items = cached.items; fileListState.items = cached.items;
iframeLoader.classList.add('hidden');
renderFileGroups(link); renderFileGroups(link);
return; return;
} }
@@ -1393,8 +1394,8 @@
} }
} }
// If still unauthorized or server missing token, prefer stale cache or open-in-new-tab without forcing reauth // If still unauthorized, prefer stale cache or open-in-new-tab without forcing reauth
if (resp.status === 401 || resp.status === 500) { if (resp.status === 401) {
const cachedAgain = fileCache.get(link); const cachedAgain = fileCache.get(link);
if (cachedAgain) { if (cachedAgain) {
fileListState.items = cachedAgain.items; fileListState.items = cachedAgain.items;
+26
View File
@@ -58,9 +58,35 @@
errorEl.classList.add('hidden'); errorEl.classList.add('hidden');
try { try {
// Step 1: Authenticate with PocketBase via Microsoft OAuth
const authData = await pb.collection('users').authWithOAuth2({ const authData = await pb.collection('users').authWithOAuth2({
provider: 'microsoft', provider: 'microsoft',
}); });
// Step 2: Try to get Graph token from PB response
let graphToken = (
authData?.meta?.graphAccessToken ||
authData?.meta?.graph_token ||
authData?.meta?.graphToken ||
authData?.meta?.accessToken ||
authData?.meta?.access_token ||
authData?.meta?.token ||
''
);
// Step 3: If no Graph token from PB, use the OAuth token as the Graph token
// (PB's Microsoft OAuth should return a token that works with Graph API)
if (!graphToken && authData?.meta?.rawUser) {
// The OAuth token from Microsoft should work for Graph API calls
graphToken = authData?.token || authData?.meta?.accessToken || '';
}
if (graphToken) {
const expiresAt = authData?.meta?.graphTokenExpiresAt || new Date(Date.now() + 3600000).toISOString();
await tokenManager.setToken(graphToken, expiresAt);
console.log('[Login] Graph token stored successfully');
}
displayUserInfo(authData); displayUserInfo(authData);
} catch (error) { } catch (error) {
console.error('Login failed:', error); console.error('Login failed:', error);
+8 -23
View File
@@ -136,18 +136,15 @@ class TokenManager {
*/ */
async refreshToken() { async refreshToken() {
if (this.isRefreshing) { if (this.isRefreshing) {
console.log('[TokenManager] Refresh already in progress');
return this.token; // Return existing token while refresh ongoing return this.token; // Return existing token while refresh ongoing
} }
if (!this.pb?.authStore?.isValid) { if (!this.pb?.authStore?.isValid) {
console.log('[TokenManager] PB session invalid, cannot refresh');
return null; return null;
} }
this.isRefreshing = true; this.isRefreshing = true;
try { try {
console.log('[TokenManager] Refreshing token...');
const authData = await this.pb.collection('users').authRefresh(); const authData = await this.pb.collection('users').authRefresh();
const meta = authData?.meta || {}; const meta = authData?.meta || {};
@@ -156,17 +153,16 @@ class TokenManager {
if (newToken) { if (newToken) {
await this.setToken(newToken, newExpiry); await this.setToken(newToken, newExpiry);
console.log('[TokenManager] Token refreshed successfully'); this.retryAttempts = 0;
this.retryAttempts = 0; // Reset retry counter on success
return newToken; return newToken;
} else { } else {
console.warn('[TokenManager] No token in refresh response'); // PB authRefresh doesn't return Graph tokens - this is expected
return null; // Token must be obtained during initial OAuth flow
return this.token; // Return existing token if we have one
} }
} catch (err) { } catch (err) {
console.error('[TokenManager] Refresh failed:', err.message); console.error('[TokenManager] PB authRefresh failed:', err.message);
this.queueRefreshRetry(); return this.token; // Return stale token on error
return this.token; // Return stale token while retrying
} finally { } finally {
this.isRefreshing = false; this.isRefreshing = false;
} }
@@ -176,22 +172,11 @@ class TokenManager {
* Queue retry with exponential backoff * Queue retry with exponential backoff
*/ */
queueRefreshRetry() { queueRefreshRetry() {
if (this.retryAttempts >= this.maxRetries) { // Disable retry queue since PB authRefresh won't return Graph tokens
console.error('[TokenManager] Max refresh retries reached'); // Graph tokens must be obtained through the initial OAuth flow
return; return;
} }
this.retryAttempts++;
const backoffMs = Math.pow(2, this.retryAttempts - 1) * 1000; // 1s, 2s, 4s, 8s, 16s
console.log(`[TokenManager] Retry ${this.retryAttempts}/${this.maxRetries} in ${backoffMs}ms`);
setTimeout(() => {
this.refreshToken().catch(err => {
console.error('[TokenManager] Retry failed:', err.message);
});
}, backoffMs);
}
/** /**
* Start continuous refresh cycle * Start continuous refresh cycle
*/ */