- Implemented Graph token lifecycle management with 60s safety buffer - Added automatic token refresh scheduled 5min before expiry - Fixed token expiration handling with env variable fallback - Resolved SharePoint link parsing for both URL formats (RootFolder param and direct pathname) - Handled URL-encoded spaces in file paths with proper decoding - Implemented internal file viewer modal staying within app context - Added file categorization system (Manager Info, Contracts, Plans, Submittals, Other) - Integrated SVG icons for file types (PDF, Word, Excel, Presentation, Images) - Added search/filter capability for files in folder view - Enhanced auth module with improved button click debugging - Fixed mobile responsiveness for file listing Changes: - Mode2Svelte/src/routes/+page.svelte: Complete component rewrite with token management - Mode2Svelte/src/lib/auth/frontend.ts: Added comprehensive logging for auth flow - Mode2Svelte/src/routes/api/job-files/+server.ts: Created file access endpoint - Mode2Svelte/src/routes/api/jobs/list/+server.ts: Added jobs list endpoint Status: Files now load and display in grouped categories with internal viewer Next: Fix mobile app authentication issue and further refinements
Mode2Svelte - Advanced SvelteKit Auth Testing Suite
An enhanced SvelteKit-based testing environment for advanced authentication workflows with Microsoft Azure MSAL and PocketBase. This is an extended implementation of Mode1Svelte with additional testing capabilities.
Tech Stack
- Framework: SvelteKit 2.x with TypeScript
- Backend: Node.js Adapter (production-ready)
- Styling: Tailwind CSS 4
- Authentication:
- Azure MSAL Node (@azure/msal-node) - Microsoft Graph token management
- PocketBase - User OAuth2 and token validation
- Build Tool: Vite (integrated with SvelteKit)
- Runtime: Node.js 18+
Features
✅ Frontend Authentication (PocketBase)
- OAuth2 login initialization with Microsoft
- Auth state management and retrieval
- Token refresh and validation
- Session persistence
- Automatic logout on invalid tokens
✅ Backend Token Management (Microsoft Graph)
- App-only token acquisition via MSAL
- Automatic token caching with 60-second expiration buffer
- Token refresh on demand
- JWT payload inspection
✅ Token Validation & Comparison
- PocketBase user token validation
- User record retrieval from tokens
- Side-by-side token comparison (Graph vs PocketBase)
- Token payload analysis
✅ Interactive Testing Dashboard
- Real-time authentication status
- Visual token testing interface
- API endpoint testing
- Response inspection
Project Structure
Mode1Svelte/
├── src/
│ ├── lib/
│ │ └── auth/
│ │ ├── types.ts # TypeScript interfaces
│ │ ├── backend.ts # Backend auth classes (MSAL, PocketBase)
│ │ └── frontend.ts # Frontend PocketBase auth class
│ ├── routes/
│ │ ├── +layout.svelte # App layout
│ │ ├── +page.svelte # Main dashboard
│ │ └── api/
│ │ └── auth/
│ │ ├── config/ # GET /api/auth/config
│ │ ├── graph/ # GET /api/auth/graph/token
│ │ ├── validate-pb-token/ # POST /api/auth/validate-pb-token
│ │ ├── refresh-graph/ # POST /api/auth/refresh-graph
│ │ └── compare-tokens/ # POST /api/auth/compare-tokens
│ └── app.css # Tailwind directives
├── static/ # Static assets
├── package.json # Dependencies
├── svelte.config.js # SvelteKit config (Node adapter)
├── tailwind.config.js # Tailwind CSS config
├── vite.config.ts # Vite config
└── tsconfig.json # TypeScript config
Installation
cd Mode1Svelte
npm install
Environment Setup
Ensure your .env file or environment variables are set:
export CLIENT_ID="<Azure Client ID>"
export TENANT_ID="<Azure Tenant ID>"
export CLIENT_SECRET="<Azure Client Secret>"
export PB_URL="<PocketBase URL>"
export PB_DB="<PocketBase Database URL>"
export PORT=5173
For development, create /home/admin/secrets/.env:
CLIENT_ID=your_client_id
TENANT_ID=your_tenant_id
CLIENT_SECRET=your_client_secret
PB_URL=https://pocketbase.example.com
PB_DB=https://pocketbase.example.com
Running the Application
Development Mode
npm run dev
Starts the dev server at http://localhost:5173 with hot reloading.
Production Build
npm run build
npm start
Builds the application and runs the Node.js server.
Type Checking
npm run check
Run TypeScript type checking across the project.
API Endpoints
GET /api/auth/config
Returns frontend-safe configuration for PocketBase OAuth setup.
Response:
{
"pbUrl": "https://pocketbase.example.com",
"provider": "microsoft",
"collection": "Users"
}
GET /api/auth/graph/token
Fetches a Microsoft Graph token for backend API access.
Response:
{
"success": true,
"token": "eyJ0eXAiOiJKV1Q...",
"fullToken": "eyJ0eXAiOiJKV1QiLCJhbGc...",
"expiresOn": "2026-01-23T02:15:00.000Z",
"isValid": true,
"tokenDetails": {
"aud": "https://graph.microsoft.com",
"iss": "https://sts.windows.net/tenant-id",
"scp": "..."
}
}
POST /api/auth/validate-pb-token
Validates a PocketBase user token and retrieves user information.
Request:
{
"pbToken": "user_token_string"
}
Response:
{
"valid": true,
"user": {
"id": "user_id",
"email": "user@example.com",
"name": "User Name"
}
}
POST /api/auth/refresh-graph
Clears the cached Graph token and acquires a new one.
Response:
{
"success": true,
"refreshed": true,
"expiresOn": "2026-01-23T02:15:00.000Z"
}
POST /api/auth/compare-tokens
Compares Graph token (backend) and PocketBase token (user) to demonstrate their differences.
Request:
{
"pbToken": "user_token_string"
}
Response:
{
"success": true,
"comparison": {
"graph_token": {
"issuer": "https://sts.windows.net/tenant",
"audience": "https://graph.microsoft.com",
"app": "App Name",
"scopes": "...",
"issued_at": "2026-01-23T01:15:00.000Z",
"expires_at": "2026-01-23T02:15:00.000Z",
"type": "Microsoft Graph Token (Backend/App-only)",
"source": "@azure/msal-node",
"purpose": "Backend API calls to Microsoft Graph"
},
"pocketbase_token": {
"type": "PocketBase User Token (Frontend/User)",
"source": "PocketBase OAuth2 flow",
"authenticated_user": "user@example.com"
},
"are_different": true
}
}
Authentication Flow
Frontend (Browser)
- User clicks "Login with Microsoft"
- PocketBase initiates OAuth2 flow with Microsoft provider
- Microsoft redirects back with authorization code
- PocketBase exchanges code for user token
- Token stored in PocketBase auth store
- User dashboard updates with authenticated state
Backend (Server)
- Application starts with MSAL configuration
- On first API request, acquires Graph token using client credentials
- Token cached for 55 minutes (60-minute lifetime - 5-minute buffer)
- Subsequent requests use cached token
- Token automatically refreshed when expired
Development Notes
- CORS: Configured for
localhost:5173and production URLs - Token Caching: Graph tokens cached in memory; refresh on demand with
/api/auth/refresh-graph - Error Handling: Comprehensive error messages with specific failure reasons
- Type Safety: Full TypeScript support throughout frontend and backend
- SvelteKit Routing: File-based routing with
+page.svelteand+server.tsfiles
Comparison with Mode1 (Hono/Bun)
| Feature | Mode1Svelte | Mode1 |
|---|---|---|
| Framework | SvelteKit 2 | SvelteKit 4 (old) |
| Backend | Node.js Adapter | Hono + Bun |
| Frontend | Svelte Components | HTML + Vanilla JS |
| Styling | Tailwind CSS | CSS (custom) |
| Build Tool | Vite | Vite |
| API Routes | /routes/api/ |
/routes/api/ |
| Auth Module | /lib/auth/ |
/routes/api/ |
| Type Safety | Full TypeScript | TypeScript (partial) |
| Production Ready | ✅ Yes | ⚠️ Experimental |
Troubleshooting
Token Acquisition Fails
- Verify
CLIENT_ID,TENANT_ID, andCLIENT_SECRETare correct - Ensure the Azure application is configured for client credentials flow
- Check that the application has Graph API permissions
PocketBase Token Validation Fails
- Verify
PB_URLandPB_DBare correct - Ensure the user is properly logged in via OAuth
- Check that PocketBase is running and accessible
Login Button Not Appearing
- Ensure JavaScript is enabled
- Check browser console for errors
- Verify that
loginBtnHTML element ID matches configuration
Links
License
Private - Job Info Testing Suite
Developing
Once you've created a project and installed dependencies with npm install (or pnpm install or yarn), start a development server:
npm run dev
# or start the server and open the app in a new browser tab
npm run dev -- --open
Building
To create a production version of your app:
npm run build
You can preview the production build with npm run preview.
To deploy your app, you may need to install an adapter for your target environment.