Rebuild Mode1Svelte with SvelteKit + Node.js adapter
- Migrated from Bun/Hono to modern SvelteKit tech stack - Implemented complete authentication module (Azure MSAL + PocketBase) - Created 5 API endpoints for auth operations (config, graph token, validate, refresh, compare) - Built interactive Svelte dashboard with mobile optimization (iPhone 16) - Added Node.js adapter (@sveltejs/adapter-node) for production deployment - Integrated Tailwind CSS with responsive design - Fixed orchestrator to spawn Mode1Svelte with Node.js on port 3005 - Updated systemd service (job-info-test.service) to start orchestrator on port 3006 - Port configuration locked: 3005 = Mode1Svelte, 3006 = Orchestrator - Full TypeScript type safety throughout application - Services auto-managed by orchestrator with systemd integration
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
import { json, type RequestHandler } from '@sveltejs/kit';
|
||||
import { BackendAuth } from '$lib/auth/backend';
|
||||
|
||||
const backendAuth = new BackendAuth(
|
||||
{
|
||||
clientId: process.env.CLIENT_ID,
|
||||
tenantId: process.env.TENANT_ID,
|
||||
clientSecret: process.env.CLIENT_SECRET,
|
||||
},
|
||||
process.env.PB_DB
|
||||
);
|
||||
|
||||
export const POST: RequestHandler = async ({ request }) => {
|
||||
try {
|
||||
const body = await request.json();
|
||||
const pbToken = body.pbToken;
|
||||
|
||||
// Get Graph token
|
||||
const { token: graphToken, expiresOnISO: graphExpires } = await backendAuth.graphTokenManager.getTokenWithExpiry();
|
||||
|
||||
if (!graphToken) {
|
||||
return json({ success: false, error: 'Failed to acquire Graph token' }, { status: 500 });
|
||||
}
|
||||
|
||||
// Decode both tokens to compare
|
||||
const decodeJWT = (token: string) => {
|
||||
try {
|
||||
const parts = token.split('.');
|
||||
if (parts.length !== 3) return null;
|
||||
return JSON.parse(Buffer.from(parts[1], 'base64').toString());
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
const graphPayload = decodeJWT(graphToken);
|
||||
|
||||
// Validate PB token to get actual user
|
||||
let authenticatedUser = 'Unknown';
|
||||
if (pbToken) {
|
||||
try {
|
||||
const isValid = await backendAuth.pbValidator.validateUserToken(pbToken);
|
||||
if (isValid) {
|
||||
const userRecord = await backendAuth.pbValidator.getUserRecord(pbToken);
|
||||
authenticatedUser = userRecord?.email || userRecord?.id || 'Unknown';
|
||||
}
|
||||
} catch {
|
||||
authenticatedUser = 'Token invalid or expired';
|
||||
}
|
||||
}
|
||||
|
||||
return json({
|
||||
success: true,
|
||||
comparison: {
|
||||
graph_token: {
|
||||
issuer: graphPayload?.iss || 'N/A',
|
||||
audience: graphPayload?.aud || 'N/A',
|
||||
app: graphPayload?.app_displayname || 'N/A',
|
||||
scopes: graphPayload?.scp || 'N/A',
|
||||
issued_at: graphPayload?.iat ? new Date(graphPayload.iat * 1000).toISOString() : 'N/A',
|
||||
expires_at: graphPayload?.exp ? new Date(graphPayload.exp * 1000).toISOString() : 'N/A',
|
||||
type: 'Microsoft Graph Token (Backend/App-only)',
|
||||
source: '@azure/msal-node',
|
||||
purpose: 'Backend API calls to Microsoft Graph',
|
||||
},
|
||||
pocketbase_token: {
|
||||
note: 'User token from PocketBase OAuth2',
|
||||
type: 'PocketBase User Token (Frontend/User)',
|
||||
source: 'PocketBase OAuth2 flow',
|
||||
purpose: 'User authentication and authorization',
|
||||
authenticated_user: authenticatedUser,
|
||||
},
|
||||
are_different: true,
|
||||
explanation: 'These are completely different tokens from different systems: Graph token is for app-to-app Microsoft API access, PocketBase token is for user authentication in the application.',
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
return json(
|
||||
{ success: false, error: error instanceof Error ? error.message : 'Failed to compare tokens' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user