Fix: Add fallback token retrieval endpoint and improved token extraction debugging
This commit is contained in:
@@ -82,6 +82,48 @@ app.get('/version', (c) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Get Graph token from PocketBase auth data
|
||||||
|
app.get('/api/graph-token', async (c) => {
|
||||||
|
try {
|
||||||
|
const authHeader = c.req.header('Authorization');
|
||||||
|
if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
||||||
|
return c.json({ error: 'Unauthorized' }, 401);
|
||||||
|
}
|
||||||
|
|
||||||
|
const pbToken = authHeader.substring(7);
|
||||||
|
|
||||||
|
// Fetch the authenticated user's data from PocketBase
|
||||||
|
const response = await fetch('https://pocketbase.ccllc.pro/api/collections/users/auth-refresh', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Authorization': `Bearer ${pbToken}` }
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
return c.json({ error: 'Failed to refresh auth' }, response.status);
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
const meta = data?.meta || {};
|
||||||
|
|
||||||
|
// Extract Graph token from all possible locations
|
||||||
|
const graphToken =
|
||||||
|
meta?.graphAccessToken ||
|
||||||
|
meta?.graph_token ||
|
||||||
|
meta?.graphToken ||
|
||||||
|
meta?.accessToken ||
|
||||||
|
meta?.access_token ||
|
||||||
|
meta?.token ||
|
||||||
|
meta?.rawToken ||
|
||||||
|
meta?.authData?.access_token ||
|
||||||
|
'';
|
||||||
|
|
||||||
|
return c.json({ token: graphToken });
|
||||||
|
} catch (err) {
|
||||||
|
logLine('logs/error.log', `graph-token endpoint error: ${(err as Error)?.message || String(err)}`);
|
||||||
|
return c.json({ error: 'Failed to get token', token: '' }, 500);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Jobs endpoint with Redis caching
|
// Jobs endpoint with Redis caching
|
||||||
app.get('/api/jobs', async (c) => {
|
app.get('/api/jobs', async (c) => {
|
||||||
const page = parseInt(c.req.query('page') || '1');
|
const page = parseInt(c.req.query('page') || '1');
|
||||||
|
|||||||
@@ -280,6 +280,7 @@
|
|||||||
let refreshPromise = null;
|
let refreshPromise = null;
|
||||||
let lastRefreshTime = 0;
|
let lastRefreshTime = 0;
|
||||||
const REFRESH_COOLDOWN = 2000; // 2 second cooldown between refreshes
|
const REFRESH_COOLDOWN = 2000; // 2 second cooldown between refreshes
|
||||||
|
let refreshFailureCount = 0;
|
||||||
|
|
||||||
const refreshGraphToken = async () => {
|
const refreshGraphToken = async () => {
|
||||||
try {
|
try {
|
||||||
@@ -290,7 +291,9 @@
|
|||||||
|
|
||||||
// If refreshed recently, return cached token
|
// If refreshed recently, return cached token
|
||||||
if (Date.now() - lastRefreshTime < REFRESH_COOLDOWN) {
|
if (Date.now() - lastRefreshTime < REFRESH_COOLDOWN) {
|
||||||
return getGraphToken();
|
const cached = getGraphToken();
|
||||||
|
if (cached) return cached;
|
||||||
|
// Even within cooldown, if no cached token, still try refresh
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start new refresh
|
// Start new refresh
|
||||||
@@ -299,9 +302,22 @@
|
|||||||
const authData = await pb.collection('users').authRefresh();
|
const authData = await pb.collection('users').authRefresh();
|
||||||
const meta = authData?.meta || pb?.authStore?.model?.meta || {};
|
const meta = authData?.meta || pb?.authStore?.model?.meta || {};
|
||||||
const token = extractGraphToken(meta);
|
const token = extractGraphToken(meta);
|
||||||
if (token) localStorage.setItem(GRAPH_TOKEN_KEY, token);
|
|
||||||
lastRefreshTime = Date.now();
|
if (token) {
|
||||||
return token || '';
|
localStorage.setItem(GRAPH_TOKEN_KEY, token);
|
||||||
|
lastRefreshTime = Date.now();
|
||||||
|
refreshFailureCount = 0;
|
||||||
|
console.log('✓ Graph token refreshed');
|
||||||
|
return token;
|
||||||
|
} else {
|
||||||
|
console.warn('Graph token missing from auth response');
|
||||||
|
refreshFailureCount++;
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.warn('Token refresh request failed:', err?.message||err);
|
||||||
|
refreshFailureCount++;
|
||||||
|
throw err;
|
||||||
} finally {
|
} finally {
|
||||||
refreshPromise = null;
|
refreshPromise = null;
|
||||||
}
|
}
|
||||||
@@ -310,8 +326,18 @@
|
|||||||
return await refreshPromise;
|
return await refreshPromise;
|
||||||
} catch(err){
|
} catch(err){
|
||||||
refreshPromise = null;
|
refreshPromise = null;
|
||||||
console.warn('Graph token refresh failed:', err?.message||err);
|
console.error('❌ Graph token refresh failed completely:', err?.message||err);
|
||||||
return getGraphToken(); // Return cached token if refresh fails
|
// If refresh failed multiple times, force sign-in
|
||||||
|
if (refreshFailureCount >= 2) {
|
||||||
|
console.warn('Token refresh failed multiple times. Forcing sign-in.');
|
||||||
|
localStorage.removeItem(GRAPH_TOKEN_KEY);
|
||||||
|
try { pb?.authStore?.clear?.(); } catch {}
|
||||||
|
try { localStorage.removeItem('pocketbase_auth'); } catch {}
|
||||||
|
try { sessionStorage.clear(); } catch {}
|
||||||
|
window.location.href = 'signin.html?expired=1';
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
return '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -101,13 +101,51 @@
|
|||||||
const email = authData?.meta?.rawUser?.email || authData?.record?.email || pb.authStore.model?.email || 'Not available';
|
const email = authData?.meta?.rawUser?.email || authData?.record?.email || pb.authStore.model?.email || 'Not available';
|
||||||
const graphToken = extractGraphToken(authData);
|
const graphToken = extractGraphToken(authData);
|
||||||
console.log('Extracted Graph token:', graphToken ? graphToken.substring(0, 30) + '...' : 'NOT FOUND');
|
console.log('Extracted Graph token:', graphToken ? graphToken.substring(0, 30) + '...' : 'NOT FOUND');
|
||||||
|
console.log('Full meta object:', JSON.stringify(authData?.meta, null, 2));
|
||||||
|
|
||||||
if (graphToken) {
|
if (graphToken) {
|
||||||
localStorage.setItem(GRAPH_TOKEN_KEY, graphToken);
|
localStorage.setItem(GRAPH_TOKEN_KEY, graphToken);
|
||||||
localStorage.removeItem(GRAPH_REAUTH_FLAG);
|
localStorage.removeItem(GRAPH_REAUTH_FLAG);
|
||||||
|
console.log('✓ Graph token stored');
|
||||||
|
} else {
|
||||||
|
console.error('❌ Graph token NOT found in auth response!');
|
||||||
|
console.error('Available meta keys:', Object.keys(authData?.meta || {}));
|
||||||
|
// If token not in response, try fetching it from the backend
|
||||||
|
console.log('Attempting to fetch token from backend...');
|
||||||
|
fetchTokenFromBackend().then(token => {
|
||||||
|
if (token) {
|
||||||
|
localStorage.setItem(GRAPH_TOKEN_KEY, token);
|
||||||
|
console.log('✓ Graph token fetched from backend');
|
||||||
|
} else {
|
||||||
|
console.warn('⚠ Graph token could not be obtained from backend');
|
||||||
|
}
|
||||||
|
showAuthedUI(displayName, email);
|
||||||
|
}).catch(err => {
|
||||||
|
console.error('Failed to fetch token from backend:', err);
|
||||||
|
showAuthedUI(displayName, email);
|
||||||
|
});
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
showAuthedUI(displayName, email);
|
showAuthedUI(displayName, email);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function fetchTokenFromBackend() {
|
||||||
|
try {
|
||||||
|
const response = await fetch('/api/graph-token', {
|
||||||
|
headers: {
|
||||||
|
'Authorization': `Bearer ${pb.authStore.token}`
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (response.ok) {
|
||||||
|
const data = await response.json();
|
||||||
|
return data.token || '';
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.warn('Token fetch error:', err.message);
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
const params = new URLSearchParams(window.location.search);
|
const params = new URLSearchParams(window.location.search);
|
||||||
const reauth = params.get('reauth') === '1';
|
const reauth = params.get('reauth') === '1';
|
||||||
|
|||||||
Reference in New Issue
Block a user