321 lines
11 KiB
Markdown
321 lines
11 KiB
Markdown
================================================================================
|
|
QUICK START: Integrating Unified Auth into NewApproach
|
|
================================================================================
|
|
|
|
This guide shows how to integrate the auth system into your NewApproach project.
|
|
|
|
================================================================================
|
|
STEP 1: SETUP ENVIRONMENT VARIABLES
|
|
================================================================================
|
|
|
|
Create or update .env file in NewApproach root:
|
|
|
|
```
|
|
# PocketBase
|
|
POCKETBASE_URL=http://localhost:8090
|
|
POCKETBASE_SERVICE_EMAIL=service@example.com
|
|
POCKETBASE_SERVICE_PASSWORD=your_service_password
|
|
|
|
# Microsoft Graph (Service Principal)
|
|
GRAPH_TENANT_ID=your-tenant-id
|
|
GRAPH_CLIENT_ID=your-client-id
|
|
GRAPH_CLIENT_SECRET=your-client-secret
|
|
```
|
|
|
|
Note: .env should NOT be committed to git. Add to .gitignore.
|
|
|
|
================================================================================
|
|
STEP 2: UPDATE FRONTEND (public/index.html)
|
|
================================================================================
|
|
|
|
Current state: public/index.html loads static app
|
|
|
|
Required changes:
|
|
1. Add PocketBase SDK
|
|
2. Add auth module
|
|
3. Initialize auth on page load
|
|
4. Use tokens for API calls
|
|
|
|
```html
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>NewApproach</title>
|
|
<link rel="stylesheet" href="/output.css">
|
|
|
|
<!-- PocketBase SDK (REQUIRED for auth) -->
|
|
<script src="https://cdn.jsdelivr.net/npm/pocketbase@0.26.5/dist/pocketbase.umd.js"></script>
|
|
</head>
|
|
<body class="bg-gray-50">
|
|
<div id="app"></div>
|
|
|
|
<script type="module">
|
|
// Import auth module
|
|
import Auth from '/auth.unified.ts';
|
|
|
|
// Initialize auth on page load
|
|
async function init() {
|
|
try {
|
|
// Initialize auth with both PocketBase and Graph patterns
|
|
await Auth.init('pb+graph', {
|
|
pbUrl: 'http://localhost:8090'
|
|
});
|
|
|
|
// Get tokens (this shows login popup if needed)
|
|
const pbUserToken = await Auth.getToken('pb-user');
|
|
const graphToken = await Auth.getToken('graph-user');
|
|
|
|
// Get user info
|
|
const { displayName, email } = Auth.getUserInfo();
|
|
console.log(`Logged in as: ${displayName} (${email})`);
|
|
|
|
// Now load the app
|
|
await loadApp(pbUserToken, graphToken);
|
|
} catch (err) {
|
|
console.error('Auth initialization failed:', err);
|
|
document.getElementById('app').innerHTML = '<p style="color: red;">Authentication failed. Please refresh.</p>';
|
|
}
|
|
}
|
|
|
|
async function loadApp(pbToken, graphToken) {
|
|
const app = document.getElementById('app');
|
|
|
|
app.innerHTML = `
|
|
<div class="min-h-screen flex flex-col items-center justify-center bg-gradient-to-br from-blue-50 to-indigo-100">
|
|
<div class="bg-white rounded-lg shadow-lg p-8 max-w-md w-full">
|
|
<h1 class="text-3xl font-bold text-gray-800 mb-2">NewApproach</h1>
|
|
<p class="text-gray-600 mb-6">Full-stack TypeScript + Hono + TailwindCSS</p>
|
|
|
|
<div class="mb-4 p-4 bg-gray-50 rounded">
|
|
<p class="text-sm text-gray-600"><strong>Status:</strong> Authenticated</p>
|
|
<p class="text-sm text-gray-600"><strong>PB Token:</strong> ${pbToken.substring(0, 20)}...</p>
|
|
<p class="text-sm text-gray-600"><strong>Graph Token:</strong> ${graphToken ? graphToken.substring(0, 20) + '...' : 'Not available'}</p>
|
|
</div>
|
|
|
|
<button
|
|
id="fetchBtn"
|
|
class="w-full bg-blue-500 hover:bg-blue-600 text-white font-semibold py-2 px-4 rounded transition"
|
|
>
|
|
Fetch API Info
|
|
</button>
|
|
|
|
<button
|
|
id="logoutBtn"
|
|
class="w-full mt-2 bg-gray-500 hover:bg-gray-600 text-white font-semibold py-2 px-4 rounded transition"
|
|
>
|
|
Logout
|
|
</button>
|
|
|
|
<div id="result" class="mt-6 p-4 bg-gray-50 rounded hidden">
|
|
<pre id="resultContent" class="text-sm text-gray-700 whitespace-pre-wrap"></pre>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
|
|
// Fetch with token
|
|
document.getElementById('fetchBtn').addEventListener('click', async () => {
|
|
try {
|
|
const response = await fetch('/api/info', {
|
|
headers: {
|
|
'Authorization': `Bearer ${pbToken}`,
|
|
'X-Graph-Token': graphToken
|
|
}
|
|
});
|
|
const data = await response.json();
|
|
document.getElementById('result').classList.remove('hidden');
|
|
document.getElementById('resultContent').textContent = JSON.stringify(data, null, 2);
|
|
} catch (err) {
|
|
alert('API call failed: ' + err.message);
|
|
}
|
|
});
|
|
|
|
// Logout
|
|
document.getElementById('logoutBtn').addEventListener('click', () => {
|
|
Auth.clearAllTokens();
|
|
location.reload();
|
|
});
|
|
}
|
|
|
|
// Start
|
|
init();
|
|
</script>
|
|
|
|
<script src="/app.js"></script>
|
|
</body>
|
|
</html>
|
|
```
|
|
|
|
================================================================================
|
|
STEP 3: UPDATE BACKEND (src/backend/server.ts)
|
|
================================================================================
|
|
|
|
Current state: Basic Hono server with /api/health and /api/info
|
|
|
|
Required changes:
|
|
1. Import auth module
|
|
2. Initialize backend auth
|
|
3. Add service token endpoints
|
|
4. Use tokens in routes
|
|
|
|
```typescript
|
|
import { Hono } from 'hono';
|
|
import { serveStatic } from 'hono/bun';
|
|
import backendAuth, { serviceTokenMiddleware, createTokenEndpoint, createRefreshEndpoint } from './auth';
|
|
|
|
const app = new Hono();
|
|
|
|
// Initialize backend auth (loads from env vars)
|
|
backendAuth.init({
|
|
pbUrl: process.env.POCKETBASE_URL
|
|
});
|
|
|
|
// Middleware: Inject service tokens into context
|
|
app.use('/*', serviceTokenMiddleware());
|
|
|
|
// Static files
|
|
app.use('/*', serveStatic({ root: './public' }));
|
|
|
|
// Health check
|
|
app.get('/api/health', (c) => {
|
|
return c.json({ status: 'ok', timestamp: new Date().toISOString() });
|
|
});
|
|
|
|
// Info endpoint (uses tokens)
|
|
app.get('/api/info', (c) => {
|
|
const pbToken = c.get('pbServiceToken');
|
|
const graphToken = c.get('graphServiceToken');
|
|
|
|
return c.json({
|
|
name: 'NewApproach',
|
|
version: '0.1.0',
|
|
description: 'Full-stack TypeScript + Hono + TailwindCSS',
|
|
authStatus: {
|
|
pbServiceToken: !!pbToken,
|
|
graphServiceToken: !!graphToken
|
|
}
|
|
});
|
|
});
|
|
|
|
// Example: Use service tokens to call external APIs
|
|
app.get('/api/graph-data', async (c) => {
|
|
try {
|
|
const graphToken = await backendAuth.getGraphServicePrincipalToken();
|
|
|
|
// Call Microsoft Graph API
|
|
const response = await fetch('https://graph.microsoft.com/v1.0/me', {
|
|
headers: { 'Authorization': `Bearer ${graphToken}` }
|
|
});
|
|
|
|
const data = await response.json();
|
|
return c.json({ success: true, data });
|
|
} catch (err) {
|
|
return c.json({ success: false, error: (err as Error).message }, 500);
|
|
}
|
|
});
|
|
|
|
// Register token endpoints
|
|
createTokenEndpoint(app);
|
|
createRefreshEndpoint(app);
|
|
|
|
// SPA fallback
|
|
app.get('*', serveStatic({ path: './public/index.html', root: './public' }));
|
|
|
|
// Start server
|
|
const port = process.env.PORT || 3000;
|
|
export default {
|
|
port,
|
|
fetch: app.fetch,
|
|
};
|
|
|
|
console.log(`🚀 Server running on http://localhost:${port}`);
|
|
```
|
|
|
|
================================================================================
|
|
STEP 4: COMPILE & RUN
|
|
================================================================================
|
|
|
|
```bash
|
|
cd /home/admin/Job-Info/NewApproach
|
|
|
|
# Install dependencies (if needed)
|
|
bun install
|
|
|
|
# Compile TypeScript
|
|
bun run typecheck
|
|
|
|
# Start dev server (watches for changes)
|
|
bun run dev
|
|
```
|
|
|
|
Server starts on http://localhost:3000
|
|
|
|
================================================================================
|
|
STEP 5: TEST
|
|
================================================================================
|
|
|
|
1. Open http://localhost:3000 in browser
|
|
2. Should see "Sign in with Microsoft" button
|
|
3. Click to authenticate via PocketBase OAuth
|
|
4. After login, you should see:
|
|
- User info (if available)
|
|
- Tokens in localStorage
|
|
- "Fetch API Info" button working
|
|
- Logout button clearing tokens
|
|
|
|
Check browser console for logs:
|
|
- [Auth] Initialized with pattern...
|
|
- [Auth] PocketBase user token acquired via OAuth
|
|
- [Auth] Token stored...
|
|
|
|
================================================================================
|
|
TROUBLESHOOTING
|
|
================================================================================
|
|
|
|
ISSUE: PocketBase SDK not loading
|
|
─────────────────────────────────
|
|
Check: Is PocketBase script tag present in HTML?
|
|
<script src="https://cdn.jsdelivr.net/npm/pocketbase@0.26.5/dist/pocketbase.umd.js"></script>
|
|
|
|
────────────────────────────────────────────────────────────────────────────
|
|
|
|
ISSUE: OAuth popup is blank or fails
|
|
────────────────────────────────────
|
|
Check:
|
|
1. PocketBase is running on http://localhost:8090
|
|
2. PocketBase has OAuth configured (Settings → OAuth2)
|
|
3. PocketBase has Microsoft provider configured
|
|
4. Redirect URI in PocketBase points to your app
|
|
|
|
────────────────────────────────────────────────────────────────────────────
|
|
|
|
ISSUE: Graph token is undefined
|
|
───────────────────────────────
|
|
Check:
|
|
1. PocketBase OAuth config includes Graph scopes
|
|
2. Scopes: offline_access, User.Read, Files.Read, etc.
|
|
3. PocketBase returns token in authData.meta
|
|
|
|
────────────────────────────────────────────────────────────────────────────
|
|
|
|
ISSUE: Service tokens not working
|
|
──────────────────────────────────
|
|
Check:
|
|
1. Environment variables are set and exported
|
|
2. Service account credentials are correct
|
|
3. Credentials have required permissions in Azure/PocketBase
|
|
|
|
================================================================================
|
|
NEXT STEPS
|
|
================================================================================
|
|
|
|
1. Verify auth works with manual testing
|
|
2. Integrate actual business logic using tokens
|
|
3. Add error handling and user feedback
|
|
4. Test with real Microsoft Graph API calls
|
|
5. Deploy to production with proper security
|
|
|
|
See UNIFIED_AUTH_GUIDE.md for complete documentation.
|