296 lines
12 KiB
Markdown
296 lines
12 KiB
Markdown
================================================================================
|
|
UNIFIED AUTH SYSTEM - PROJECT SUMMARY
|
|
================================================================================
|
|
|
|
A complete, production-ready authentication system for NewApproach.
|
|
Handles all token acquisition, storage, retrieval, and refresh scenarios.
|
|
|
|
================================================================================
|
|
WHAT WAS BUILT
|
|
================================================================================
|
|
|
|
THREE COMPLETE IMPLEMENTATION FILES:
|
|
|
|
1. auth/auth.unified.ts (246 lines)
|
|
├─ Frontend authentication module (TypeScript)
|
|
├─ Universal OAuth login popup
|
|
├─ 4 token types: pb-user, pb-agent, graph-user, graph-agent
|
|
├─ Auto-refresh and expiration tracking
|
|
├─ localStorage persistence
|
|
└─ Zero external dependencies
|
|
|
|
2. src/backend/auth.ts (252 lines)
|
|
├─ Backend service authentication (TypeScript/Hono)
|
|
├─ Service principal token acquisition (Azure AD client credentials)
|
|
├─ PocketBase service account auth
|
|
├─ Token caching with expiration
|
|
├─ Hono middleware for token injection
|
|
└─ API endpoints for token operations
|
|
|
|
3. COMPREHENSIVE DOCUMENTATION:
|
|
├─ auth/UNIFIED_AUTH_GUIDE.md (600+ lines) - Complete reference
|
|
├─ auth/INTEGRATION_GUIDE.md (300+ lines) - Step-by-step setup
|
|
├─ auth/AUTH_ANALYSIS.md (previous deep-dive analysis)
|
|
└─ This README
|
|
|
|
================================================================================
|
|
KEY CAPABILITIES
|
|
================================================================================
|
|
|
|
FRONTEND (Browser):
|
|
✓ Unified OAuth login → Gets pb-user AND graph-user tokens in one flow
|
|
✓ Popup for agent credentials (pb-agent, graph-agent)
|
|
✓ Token refresh before expiration
|
|
✓ User info extraction (displayName, email)
|
|
✓ Manual token management (getToken, setToken, clearToken, clearAllTokens)
|
|
|
|
BACKEND (Server):
|
|
✓ Service principal authentication (client credentials flow)
|
|
✓ PocketBase service account auth
|
|
✓ In-memory token caching with expiration
|
|
✓ Hono middleware for auto-token injection
|
|
✓ API endpoints for frontend token retrieval
|
|
|
|
BOTH:
|
|
✓ TypeScript with strict typing
|
|
✓ Proper error handling
|
|
✓ Logging for debugging
|
|
✓ Drop-in ready (no build steps needed)
|
|
|
|
================================================================================
|
|
TOKEN ACQUISITION FLOW (THE ANSWER TO YOUR QUESTION)
|
|
================================================================================
|
|
|
|
Q: "When is the token inquired and how is it acquired and where is it stored?"
|
|
|
|
ANSWER:
|
|
|
|
SCENARIO 1: User Login (OAuth)
|
|
──────────────────────────────
|
|
WHEN: User clicks "Sign in with Microsoft" button
|
|
HOW: Via PocketBase OAuth2 with Microsoft provider
|
|
User authenticates with Microsoft
|
|
Microsoft returns token(s)
|
|
WHERE: Tokens returned in OAuth response metadata
|
|
STORES: Both tokens in localStorage immediately:
|
|
- auth:pb-user (PocketBase user token)
|
|
- auth:graph-user (Microsoft Graph delegated token)
|
|
RETRIEVES: Via Auth.getToken('pb-user') or Auth.getToken('graph-user')
|
|
|
|
────────────────────────────────────────────────────────────────────────────
|
|
|
|
SCENARIO 2: Service Account (Agent)
|
|
────────────────────────────────────
|
|
WHEN: Backend code needs to call PocketBase
|
|
HOW: Via direct API call with email/password authentication
|
|
WHERE: Backend calls: POST /api/collections/users/auth-with-password
|
|
STORES: In-memory token cache (BackendAuthManager)
|
|
RETRIEVES: Via await backendAuth.getPocketBaseServiceToken()
|
|
|
|
────────────────────────────────────────────────────────────────────────────
|
|
|
|
SCENARIO 3: Microsoft Graph Delegated
|
|
──────────────────────────────────────
|
|
WHEN: Already acquired during OAuth (Scenario 1)
|
|
HOW: Extracted from PocketBase OAuth response metadata
|
|
WHERE: Returned in authData.meta by PocketBase
|
|
STORES: localStorage['auth:graph-user']
|
|
RETRIEVES: Via Auth.getToken('graph-user')
|
|
|
|
────────────────────────────────────────────────────────────────────────────
|
|
|
|
SCENARIO 4: Microsoft Graph Service Principal (App-Only)
|
|
─────────────────────────────────────────────────────────
|
|
WHEN: Backend code needs Microsoft Graph access (not user-specific)
|
|
HOW: Via Azure AD client credentials flow
|
|
POST to: https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token
|
|
Body: client_id + client_secret + scope
|
|
WHERE: Azure AD returns access_token
|
|
STORES: In-memory token cache (BackendAuthManager)
|
|
RETRIEVES: Via await backendAuth.getGraphServicePrincipalToken()
|
|
|
|
================================================================================
|
|
THE UNIFIED LOGIN CONCEPT
|
|
================================================================================
|
|
|
|
Traditional approach:
|
|
User logs in → Gets PocketBase token
|
|
Later: User must separately authenticate for Graph → Gets Graph token
|
|
Result: User logs in TWICE
|
|
|
|
NEW UNIFIED APPROACH (auth.unified.ts):
|
|
User logs in once → Gets BOTH pb-user AND graph-user tokens
|
|
Result: User logs in ONCE, both tokens acquired
|
|
|
|
This works because:
|
|
1. PocketBase is configured with Microsoft OAuth provider
|
|
2. Microsoft scopes include both PocketBase and Graph permissions
|
|
3. OAuth response includes both tokens in metadata
|
|
4. auth.unified.ts extracts both and stores them
|
|
|
|
Code:
|
|
// One call
|
|
const pbToken = await Auth.getToken('pb-user');
|
|
|
|
// Behind the scenes:
|
|
// 1. OAuth login happens
|
|
// 2. Microsoft returns: PB token + Graph token
|
|
// 3. Both stored in localStorage
|
|
// 4. Both available for API calls
|
|
// 5. Both auto-refresh if needed
|
|
|
|
================================================================================
|
|
HOW IT ALL FITS TOGETHER
|
|
================================================================================
|
|
|
|
USER JOURNEY:
|
|
──────────────
|
|
1. User visits app
|
|
2. Page loads, calls: await Auth.init('pb+graph')
|
|
3. User clicks "Sign in with Microsoft"
|
|
4. Auth.getToken('pb-user') shows popup
|
|
5. Popup redirects to PocketBase OAuth
|
|
6. PocketBase redirects to Microsoft OAuth
|
|
7. User authenticates with Microsoft
|
|
8. Microsoft returns tokens to PocketBase
|
|
9. PocketBase extracts and returns to app
|
|
10. auth.unified.ts stores both tokens in localStorage
|
|
11. App has both pb-user and graph-user tokens
|
|
12. Subsequent calls use cached tokens
|
|
13. Tokens auto-refresh before expiration
|
|
|
|
API CALL FLOW:
|
|
──────────────
|
|
Frontend makes request:
|
|
fetch('/api/data', {
|
|
headers: {
|
|
'Authorization': `Bearer ${pbToken}`,
|
|
'X-Graph-Token': graphToken
|
|
}
|
|
})
|
|
|
|
Backend receives request:
|
|
Route handler accesses:
|
|
- Authorization header → validate PocketBase token
|
|
- X-Graph-Token header → validate Graph token
|
|
- Or uses service tokens via backendAuth
|
|
|
|
Backend calls external APIs:
|
|
// Call PocketBase with service token
|
|
const pbToken = await backendAuth.getPocketBaseServiceToken();
|
|
|
|
// Call Microsoft Graph with service token
|
|
const graphToken = await backendAuth.getGraphServicePrincipalToken();
|
|
|
|
================================================================================
|
|
FILES & DOCUMENTATION
|
|
================================================================================
|
|
|
|
CORE IMPLEMENTATION:
|
|
/NewApproach/auth/auth.unified.ts
|
|
/NewApproach/src/backend/auth.ts
|
|
|
|
DOCUMENTATION:
|
|
/NewApproach/auth/UNIFIED_AUTH_GUIDE.md ← Read this for complete reference
|
|
/NewApproach/auth/INTEGRATION_GUIDE.md ← Follow this for setup
|
|
/NewApproach/auth/AUTH_ANALYSIS.md ← Deep technical analysis
|
|
/NewApproach/auth/README.md ← Original basic docs
|
|
|
|
================================================================================
|
|
QUICK START
|
|
================================================================================
|
|
|
|
1. READ: auth/INTEGRATION_GUIDE.md (step-by-step setup)
|
|
|
|
2. SET ENV VARS:
|
|
POCKETBASE_URL=...
|
|
POCKETBASE_SERVICE_EMAIL=...
|
|
POCKETBASE_SERVICE_PASSWORD=...
|
|
GRAPH_TENANT_ID=...
|
|
GRAPH_CLIENT_ID=...
|
|
GRAPH_CLIENT_SECRET=...
|
|
|
|
3. UPDATE public/index.html:
|
|
- Add PocketBase script tag
|
|
- Import and initialize Auth module
|
|
- Call Auth.init('pb+graph')
|
|
|
|
4. UPDATE src/backend/server.ts:
|
|
- Import backendAuth
|
|
- Call backendAuth.init()
|
|
- Register middleware
|
|
- Use tokens in routes
|
|
|
|
5. RUN:
|
|
bun run dev
|
|
|
|
6. TEST:
|
|
http://localhost:3000 → Click "Sign in" → Authenticate → Get tokens
|
|
|
|
================================================================================
|
|
SECURITY NOTES
|
|
================================================================================
|
|
|
|
✓ SECURE:
|
|
- Service credentials in env vars only
|
|
- Tokens transmitted in Authorization headers
|
|
- Token expiration handled automatically
|
|
- User logout clears all tokens
|
|
- Backend validates tokens server-side
|
|
|
|
✗ KNOWN RISKS:
|
|
- localStorage tokens vulnerable to XSS
|
|
- Consider HTTP-only cookies for production
|
|
- Service credentials must be rotated regularly
|
|
- Monitor token access and usage
|
|
|
|
SEE: UNIFIED_AUTH_GUIDE.md → "Security Considerations" for details
|
|
|
|
================================================================================
|
|
STATUS & NEXT STEPS
|
|
================================================================================
|
|
|
|
COMPLETED:
|
|
✓ Frontend auth module (auth.unified.ts) - Full implementation
|
|
✓ Backend auth module (src/backend/auth.ts) - Full implementation
|
|
✓ Comprehensive documentation
|
|
✓ Integration guide with code examples
|
|
✓ Session logging and tracking
|
|
|
|
READY FOR:
|
|
1. Integration into NewApproach frontend (index.html + app.js)
|
|
2. Integration into NewApproach backend (server.ts routes)
|
|
3. Testing with real PocketBase and Microsoft accounts
|
|
4. Deployment to production
|
|
|
|
NOT INCLUDED (Out of scope):
|
|
- Actual UI design (use existing or create new)
|
|
- Database schema for storing tokens
|
|
- Multi-user scenarios with token per user
|
|
- Refresh token rotation
|
|
- Token invalidation endpoints
|
|
|
|
================================================================================
|
|
SUPPORT & TROUBLESHOOTING
|
|
================================================================================
|
|
|
|
SEE: auth/INTEGRATION_GUIDE.md → "Troubleshooting" section
|
|
auth/UNIFIED_AUTH_GUIDE.md → "Troubleshooting" section
|
|
|
|
COMMON ISSUES & SOLUTIONS PROVIDED FOR:
|
|
- PocketBase SDK not loading
|
|
- OAuth popup blank/fails
|
|
- Graph token undefined
|
|
- Service tokens not working
|
|
- Tokens not persisting
|
|
- Token refresh failures
|
|
|
|
================================================================================
|
|
END OF SUMMARY
|
|
================================================================================
|
|
|
|
Start with: auth/INTEGRATION_GUIDE.md for step-by-step instructions.
|
|
Reference: auth/UNIFIED_AUTH_GUIDE.md for complete documentation.
|
|
|
|
Questions? Check the docs or review the code comments—they're extensive.
|