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:
+275
-120
@@ -1,158 +1,313 @@
|
||||
# Mode1Svelte - Auth Module Test Suite
|
||||
# Mode1Svelte - SvelteKit Auth Testing Suite
|
||||
|
||||
Self-contained test environment for the auth-module. This version is identical to Mode1 currently, serving as a foundation for future Svelte integration.
|
||||
A complete SvelteKit-based testing environment for authentication workflows with Microsoft Azure MSAL and PocketBase. This is a modern rewrite of Mode1 using the latest SvelteKit technology stack.
|
||||
|
||||
## Structure
|
||||
## Tech Stack
|
||||
|
||||
```
|
||||
Mode1Svelte/
|
||||
├── auth-module/ # Local copy of auth-module (not linked to root)
|
||||
├── backend/ # Backend server with auth endpoints
|
||||
│ └── server.ts # Hono app with Graph token and PB validation APIs
|
||||
├── frontend/ # Frontend test interface
|
||||
│ └── index.html # Interactive test dashboard
|
||||
├── logs/ # Application logs
|
||||
├── package.json # Dependencies (auth module + Hono + PocketBase)
|
||||
└── bun.lock # Locked dependencies
|
||||
```
|
||||
- **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 Auth (PocketBaseAuth)**
|
||||
- OAuth2 login initialization
|
||||
- Auth state retrieval
|
||||
- Token refresh
|
||||
- Logout
|
||||
### ✅ 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 Auth (GraphTokenManager)**
|
||||
- Microsoft Graph token acquisition
|
||||
- Token caching (with 60s expiration buffer)
|
||||
- Cache validity checking
|
||||
- Cache refresh
|
||||
### ✅ 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
|
||||
|
||||
✓ **PocketBase Validation (PocketBaseValidator)**
|
||||
- User token validation
|
||||
- User record retrieval
|
||||
- Token comparison (Graph vs PocketBase)
|
||||
### ✅ Token Validation & Comparison
|
||||
- PocketBase user token validation
|
||||
- User record retrieval from tokens
|
||||
- Side-by-side token comparison (Graph vs PocketBase)
|
||||
- Token payload analysis
|
||||
|
||||
## Running Mode1Svelte
|
||||
### ✅ Interactive Testing Dashboard
|
||||
- Real-time authentication status
|
||||
- Visual token testing interface
|
||||
- API endpoint testing
|
||||
- Response inspection
|
||||
|
||||
### Via Orchestrator (recommended)
|
||||
## Project Structure
|
||||
|
||||
```bash
|
||||
# Switch to Mode1Svelte
|
||||
curl -X POST http://localhost:3006/switch/Mode1Svelte
|
||||
|
||||
# Check status
|
||||
curl http://localhost:3006/status
|
||||
```
|
||||
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
|
||||
```
|
||||
|
||||
### Direct
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
cd Mode1Svelte
|
||||
bun install
|
||||
PORT=3005 bun run backend/server.ts
|
||||
npm install
|
||||
```
|
||||
|
||||
Then visit: `http://localhost:3005`
|
||||
## Environment Setup
|
||||
|
||||
## Future: Svelte Integration
|
||||
|
||||
This project is set up as an independent Mode to eventually convert to SvelteKit while maintaining the same API endpoints and auth-module integration.
|
||||
|
||||
## Structure
|
||||
|
||||
```
|
||||
Mode1/
|
||||
├── auth-module/ # Local copy of auth-module (not linked to root)
|
||||
├── backend/ # Backend server with auth endpoints
|
||||
│ └── server.ts # Hono app with Graph token and PB validation APIs
|
||||
├── frontend/ # Frontend test interface
|
||||
│ └── index.html # Interactive test dashboard
|
||||
├── logs/ # Application logs
|
||||
├── package.json # Dependencies (auth module + Hono + PocketBase)
|
||||
└── bun.lock # Locked dependencies
|
||||
```
|
||||
|
||||
## Features Tested
|
||||
|
||||
✓ **Frontend Auth (PocketBaseAuth)**
|
||||
- OAuth2 login initialization
|
||||
- Auth state retrieval
|
||||
- Token refresh
|
||||
- Logout
|
||||
|
||||
✓ **Backend Auth (GraphTokenManager)**
|
||||
- Microsoft Graph token acquisition
|
||||
- Token caching (with 60s expiration buffer)
|
||||
- Cache validity checking
|
||||
- Cache refresh
|
||||
|
||||
✓ **PocketBase Validation (PocketBaseValidator)**
|
||||
- User token validation
|
||||
- User record retrieval
|
||||
|
||||
## Running Mode1
|
||||
|
||||
### Via Orchestrator (recommended)
|
||||
Ensure your `.env` file or environment variables are set:
|
||||
|
||||
```bash
|
||||
# Switch to Mode1
|
||||
curl -X POST http://localhost:3006/switch/Mode1
|
||||
|
||||
# Check status
|
||||
curl http://localhost:3006/status
|
||||
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
|
||||
```
|
||||
|
||||
### Direct
|
||||
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
|
||||
```bash
|
||||
# Install dependencies (already done)
|
||||
bun install
|
||||
|
||||
# Start server
|
||||
bun run backend/server.ts
|
||||
|
||||
# Access dashboard
|
||||
open http://localhost:3005
|
||||
npm run dev
|
||||
```
|
||||
Starts the dev server at `http://localhost:5173` with hot reloading.
|
||||
|
||||
### Production Build
|
||||
```bash
|
||||
npm run build
|
||||
npm start
|
||||
```
|
||||
Builds the application and runs the Node.js server.
|
||||
|
||||
### Type Checking
|
||||
```bash
|
||||
npm run check
|
||||
```
|
||||
Run TypeScript type checking across the project.
|
||||
|
||||
## API Endpoints
|
||||
|
||||
### Configuration
|
||||
- `GET /api/auth/config` - Get frontend configuration
|
||||
### GET `/api/auth/config`
|
||||
Returns frontend-safe configuration for PocketBase OAuth setup.
|
||||
|
||||
### Graph Token Management
|
||||
- `GET /api/auth/graph/token` - Get current Graph token (with expiration)
|
||||
- `POST /api/auth/refresh-graph` - Force refresh Graph token
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"pbUrl": "https://pocketbase.example.com",
|
||||
"provider": "microsoft",
|
||||
"collection": "Users"
|
||||
}
|
||||
```
|
||||
|
||||
### PocketBase Validation
|
||||
- `POST /api/auth/validate-pb-token` - Validate a PocketBase token
|
||||
### GET `/api/auth/graph/token`
|
||||
Fetches a Microsoft Graph token for backend API access.
|
||||
|
||||
### Health
|
||||
- `GET /health` - Health check
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"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": "..."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
### POST `/api/auth/validate-pb-token`
|
||||
Validates a PocketBase user token and retrieves user information.
|
||||
|
||||
Uses `/home/admin/secrets/.env` via auth-module:
|
||||
- `CLIENT_ID` - Microsoft application ID
|
||||
- `TENANT_ID` - Azure tenant ID
|
||||
- `CLIENT_SECRET` - Microsoft client secret
|
||||
- `PB_URL` - PocketBase frontend URL
|
||||
- `PB_DB` - PocketBase backend URL
|
||||
**Request:**
|
||||
```json
|
||||
{
|
||||
"pbToken": "user_token_string"
|
||||
}
|
||||
```
|
||||
|
||||
## Dependencies
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"valid": true,
|
||||
"user": {
|
||||
"id": "user_id",
|
||||
"email": "user@example.com",
|
||||
"name": "User Name"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
All dependencies are installed locally in `node_modules/`:
|
||||
- `hono` - Web framework
|
||||
- `pocketbase` - PocketBase client
|
||||
- `@azure/msal-node` - Microsoft authentication
|
||||
- `dotenv` - Environment variable loading
|
||||
### POST `/api/auth/refresh-graph`
|
||||
Clears the cached Graph token and acquires a new one.
|
||||
|
||||
## Notes
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"refreshed": true,
|
||||
"expiresOn": "2026-01-23T02:15:00.000Z"
|
||||
}
|
||||
```
|
||||
|
||||
- This Mode1 is **completely self-contained** with its own auth-module copy
|
||||
- No dependencies on root auth-module
|
||||
- Safe to modify and test independently
|
||||
- All secrets come from `/home/admin/secrets/.env`
|
||||
### POST `/api/auth/compare-tokens`
|
||||
Compares Graph token (backend) and PocketBase token (user) to demonstrate their differences.
|
||||
|
||||
**Request:**
|
||||
```json
|
||||
{
|
||||
"pbToken": "user_token_string"
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"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)
|
||||
1. User clicks "Login with Microsoft"
|
||||
2. PocketBase initiates OAuth2 flow with Microsoft provider
|
||||
3. Microsoft redirects back with authorization code
|
||||
4. PocketBase exchanges code for user token
|
||||
5. Token stored in PocketBase auth store
|
||||
6. User dashboard updates with authenticated state
|
||||
|
||||
### Backend (Server)
|
||||
1. Application starts with MSAL configuration
|
||||
2. On first API request, acquires Graph token using client credentials
|
||||
3. Token cached for 55 minutes (60-minute lifetime - 5-minute buffer)
|
||||
4. Subsequent requests use cached token
|
||||
5. Token automatically refreshed when expired
|
||||
|
||||
## Development Notes
|
||||
|
||||
- **CORS**: Configured for `localhost:5173` and 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.svelte` and `+server.ts` files
|
||||
|
||||
## 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`, and `CLIENT_SECRET` are 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_URL` and `PB_DB` are 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 `loginBtn` HTML element ID matches configuration
|
||||
|
||||
## Links
|
||||
|
||||
- [SvelteKit Documentation](https://svelte.dev/docs/kit)
|
||||
- [Azure MSAL Node](https://github.com/AzureAD/microsoft-authentication-library-for-js)
|
||||
- [PocketBase Documentation](https://pocketbase.io/docs/)
|
||||
- [Tailwind CSS](https://tailwindcss.com/)
|
||||
|
||||
## 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:
|
||||
|
||||
```sh
|
||||
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:
|
||||
|
||||
```sh
|
||||
npm run build
|
||||
```
|
||||
|
||||
You can preview the production build with `npm run preview`.
|
||||
|
||||
> To deploy your app, you may need to install an [adapter](https://svelte.dev/docs/kit/adapters) for your target environment.
|
||||
|
||||
Reference in New Issue
Block a user