|
| 1 | +# Phoenix Desktop Login Service Integration |
| 2 | + |
| 3 | +This document provides comprehensive documentation for integrating with the Phoenix login service in desktop applications. For browser application authentication, see `readme-login-browser-no_dist.md`. |
| 4 | + |
| 5 | +## Overview |
| 6 | + |
| 7 | +The Phoenix desktop application uses a fundamentally different authentication approach compared to browser applications. Instead of session cookies, desktop apps use API keys with enhanced security measures to prevent phishing attacks and ensure secure credential storage. |
| 8 | + |
| 9 | +**Key Files:** |
| 10 | +- `src/services/login-desktop.js` - Main desktop login implementation |
| 11 | +- `readme-login-desktop-no_dist.md` - This documentation file |
| 12 | +- `readme-login-browser-no_dist.md` - Browser authentication documentation |
| 13 | +- Kernel Mode Trust files - For secure credential storage (referenced for further reading) |
| 14 | + |
| 15 | +## Architecture Overview |
| 16 | + |
| 17 | +### Core Differences from Browser Authentication |
| 18 | + |
| 19 | +| Feature | Desktop Application | Browser Application | |
| 20 | +|---------|-------------------|-------------------| |
| 21 | +| **Authentication Method** | API Keys | Session Cookies | |
| 22 | +| **Storage** | System Keychain via Tauri APIs | Browser cookies | |
| 23 | +| **Security Layer** | Kernel Mode Trust | Domain-based security | |
| 24 | +| **Phishing Protection** | Verification Codes | Domain validation | |
| 25 | +| **Cross-window sync** | Preference-based notifications | Shared domain cookies | |
| 26 | + |
| 27 | +## Desktop Authentication Flow |
| 28 | + |
| 29 | +### 1. API Key-Based Authentication |
| 30 | + |
| 31 | +Desktop applications do **NOT** use session cookies. Instead, they use API keys that are: |
| 32 | + |
| 33 | +- Obtained through a secure authentication flow |
| 34 | +- Stored securely in the system keychain via Tauri APIs |
| 35 | +- Inaccessible to browser extensions due to Kernel Mode Trust security posture |
| 36 | +- Required with every API request |
| 37 | + |
| 38 | +### 2. Verification Code Security System |
| 39 | + |
| 40 | +To prevent phishing attacks where malicious users could send authentication URLs to unsuspecting victims, the desktop app implements a verification code system: |
| 41 | + |
| 42 | +**The Attack Vector:** |
| 43 | +- Malicious user generates an authentication URL |
| 44 | +- Sends it to victim via email/message |
| 45 | +- Victim clicks and logs in, unknowingly giving access to malicious user |
| 46 | + |
| 47 | +**The Protection:** |
| 48 | +- Desktop app generates a unique verification code for each login session |
| 49 | +- User must enter this verification code to complete authentication |
| 50 | +- Even if a victim logs in with a malicious URL, they cannot provide the verification code |
| 51 | + |
| 52 | +### 3. Auto-Verification Flow |
| 53 | + |
| 54 | +For improved user experience, the desktop app includes an automatic verification system: |
| 55 | + |
| 56 | +**Components:** |
| 57 | +- **Local Node.js Server:** Started by desktop app on a dynamically detected free port (port 0) |
| 58 | +- **Random URL Security:** Auto auth endpoint uses randomly generated URL path (`/AutoAuth${randomNonce(8)}`) for security |
| 59 | +- **Account Service Integration:** account.phcode.dev/auth communicates with the secure localhost endpoint |
| 60 | +- **Automatic Code Exchange:** Verification code automatically provided if on same machine |
| 61 | + |
| 62 | +**Browser Compatibility:** |
| 63 | +- ✅ **Chrome/Chromium:** Full auto-verification support |
| 64 | +- ✅ **Firefox:** Full auto-verification support |
| 65 | +- ❌ **Safari:** Auto-verification **BLOCKED** - Safari's security policy prevents HTTPS sites from connecting to localhost |
| 66 | +- ⚠️ **Other Browsers:** May vary based on security policies |
| 67 | + |
| 68 | +**Flow:** |
| 69 | +1. Desktop app starts local Node.js server on a dynamically detected free port |
| 70 | +2. Random secure auto auth URL is generated: `http://localhost:{port}/AutoAuth{randomNonce}` |
| 71 | +3. User initiates login, gets verification code and auto auth URL |
| 72 | +4. Desktop app sends verification code to local server via `setVerificationCode()` |
| 73 | +5. User clicks "Open in Browser" → goes to account.phcode.dev/auth |
| 74 | +6. Account service attempts GET to `{autoAuthURL}/autoVerifyCode` endpoint |
| 75 | +7. **If successful (Chrome/Firefox):** verification code automatically retrieved and used |
| 76 | +8. Account service calls `{autoAuthURL}/appVerified` to notify desktop app |
| 77 | +9. **If failed (Safari/blocked):** user manually enters verification code |
| 78 | + |
| 79 | +## Secure Credential Storage |
| 80 | + |
| 81 | +### Kernel Mode Trust Integration |
| 82 | + |
| 83 | +Desktop applications leverage Kernel Mode Trust for secure credential management: |
| 84 | + |
| 85 | +- **API Key Storage:** Securely stored in system keychain via Tauri APIs |
| 86 | +- **Extension Isolation:** External extensions cannot access credentials |
| 87 | +- **Integrated Extensions Only:** Only integrated extensions have access to Kernel Mode Trust |
| 88 | +- **Cross-Platform Security:** Tauri provides secure storage across Windows, Mac, Linux |
| 89 | + |
| 90 | +**For detailed technical implementation of Kernel Mode Trust security architecture, refer to the Kernel Mode Trust source files (out of scope for this document).** |
| 91 | + |
| 92 | +## Authentication Endpoints and APIs |
| 93 | + |
| 94 | +### Key API Endpoints |
| 95 | + |
| 96 | +#### Authentication Session Management |
| 97 | +```javascript |
| 98 | +// Get app authentication session |
| 99 | +GET ${Phoenix.config.account_url}getAppAuthSession?autoAuthPort=${authPortURL}&appName=${appName} |
| 100 | +// Response: {"isSuccess":true,"appSessionID":"uuid...","validationCode":"SWXP07"} |
| 101 | +``` |
| 102 | +
|
| 103 | +#### API Key Resolution |
| 104 | +```javascript |
| 105 | +// Resolve API key with verification code |
| 106 | +GET ${Phoenix.config.account_url}resolveAppSessionID?appSessionID=${apiKey}&validationCode=${validationCode} |
| 107 | +// Response: User profile details if valid |
| 108 | +``` |
| 109 | +
|
| 110 | +#### Session Logout |
| 111 | +```javascript |
| 112 | +// Logout session |
| 113 | +POST ${Phoenix.config.account_url}logoutSession |
| 114 | +// Body: {"appSessionID": "api_key"} |
| 115 | +``` |
| 116 | +
|
| 117 | +#### Auto-Verification Endpoints (Local Server) |
| 118 | +
|
| 119 | +The desktop app creates a local Node.js server with secure auto-authentication endpoints: |
| 120 | +
|
| 121 | +```javascript |
| 122 | +// Auto auth base URL (generated with random nonce for security) |
| 123 | +// Example: http://localhost:43521/AutoAuthDI0zAUJo |
| 124 | +const autoAuthURL = KernalModeTrust.localAutoAuthURL; |
| 125 | + |
| 126 | +// Get verification code endpoint |
| 127 | +GET {autoAuthURL}/autoVerifyCode |
| 128 | +// Response: {"code": "SWXP07"} or 404 if no code available |
| 129 | +// Headers: Access-Control-Allow-Origin: https://account.phcode.dev |
| 130 | + |
| 131 | +// App verified notification endpoint |
| 132 | +GET {autoAuthURL}/appVerified |
| 133 | +// Response: "ok" |
| 134 | +// Triggers desktop app to check login status |
| 135 | +``` |
| 136 | +
|
| 137 | +**Security Features:** |
| 138 | +- **Random URL Path:** `/AutoAuth{randomNonce(8)}` makes URL unguessable |
| 139 | +- **Origin Restrictions:** Only `https://account.phcode.dev` allowed |
| 140 | +- **One-time Use:** Verification code returned only once, then cleared |
| 141 | +- **Localhost Only:** Server binds to localhost interface only |
| 142 | + |
| 143 | +### API Request Authentication |
| 144 | + |
| 145 | +Unlike browser applications that rely on automatic cookie transmission, desktop applications must explicitly include the API key with every request: |
| 146 | + |
| 147 | +```javascript |
| 148 | +// Every API call must include the API key |
| 149 | +const userProfile = await KernalModeTrust.getCredential(KernalModeTrust.CRED_KEY_API); |
| 150 | +const apiKey = JSON.parse(userProfile).apiKey; |
| 151 | +// Include apiKey in request headers or parameters |
| 152 | +``` |
| 153 | + |
| 154 | +## Implementation Details |
| 155 | + |
| 156 | +### Login Process |
| 157 | + |
| 158 | +1. **Initiate Login:** |
| 159 | + ```javascript |
| 160 | + const appAuthSession = await _getAppAuthSession(); |
| 161 | + const {appSessionID, validationCode} = appAuthSession; |
| 162 | + ``` |
| 163 | + |
| 164 | +2. **Setup Auto-Verification:** |
| 165 | + ```javascript |
| 166 | + await setAutoVerificationCode(validationCode); |
| 167 | + ``` |
| 168 | + |
| 169 | +3. **Show Verification Dialog:** |
| 170 | + - Display verification code to user |
| 171 | + - Provide "Open in Browser" button |
| 172 | + - Allow manual code entry if auto-verification fails |
| 173 | + |
| 174 | +4. **Monitor Authentication Status:** |
| 175 | + ```javascript |
| 176 | + const resolveResponse = await _resolveAPIKey(appSessionID, validationCode); |
| 177 | + if(resolveResponse.userDetails) { |
| 178 | + // Authentication successful |
| 179 | + userProfile = resolveResponse.userDetails; |
| 180 | + await KernalModeTrust.setCredential(KernalModeTrust.CRED_KEY_API, JSON.stringify(userProfile)); |
| 181 | + } |
| 182 | + ``` |
| 183 | + |
| 184 | +### Credential Management |
| 185 | + |
| 186 | +#### Storing Credentials |
| 187 | +```javascript |
| 188 | +// Store API key securely in system keychain |
| 189 | +await KernalModeTrust.setCredential(KernalModeTrust.CRED_KEY_API, JSON.stringify(userProfile)); |
| 190 | +``` |
| 191 | + |
| 192 | +#### Retrieving Credentials |
| 193 | +```javascript |
| 194 | +// Retrieve stored credentials |
| 195 | +const savedUserProfile = await KernalModeTrust.getCredential(KernalModeTrust.CRED_KEY_API); |
| 196 | +const userProfile = JSON.parse(savedUserProfile); |
| 197 | +``` |
| 198 | + |
| 199 | +#### Removing Credentials (Logout) |
| 200 | +```javascript |
| 201 | +// Remove credentials from keychain |
| 202 | +await KernalModeTrust.removeCredential(KernalModeTrust.CRED_KEY_API); |
| 203 | +``` |
| 204 | + |
| 205 | +## Multi-Window Synchronization |
| 206 | + |
| 207 | +Desktop applications handle multi-window authentication synchronization through preferences: |
| 208 | + |
| 209 | +```javascript |
| 210 | +const PREF_USER_PROFILE_VERSION = "userProfileVersion"; |
| 211 | +
|
| 212 | +// Notify other windows of login state changes |
| 213 | +PreferencesManager.stateManager.set(PREF_USER_PROFILE_VERSION, crypto.randomUUID()); |
| 214 | +
|
| 215 | +// Listen for changes in other windows |
| 216 | +const pref = PreferencesManager.stateManager.definePreference(PREF_USER_PROFILE_VERSION, 'string', '0'); |
| 217 | +pref.watchExternalChanges(); |
| 218 | +pref.on('change', _verifyLogin); |
| 219 | +``` |
| 220 | + |
| 221 | +## Security Considerations |
| 222 | + |
| 223 | +### Phishing Attack Prevention |
| 224 | +- **Verification Code System:** Prevents unauthorized access even if user logs in with malicious URL |
| 225 | +- **Time-Limited Sessions:** Authentication sessions expire after 5 minutes |
| 226 | +- **Local Verification:** Auto-verification only works on same machine |
| 227 | + |
| 228 | +### Secure Storage |
| 229 | +- **System Keychain:** Credentials stored in OS-provided secure storage |
| 230 | +- **Tauri Security:** Leverages Tauri's security model for cross-platform protection |
| 231 | +- **Extension Isolation:** External extensions cannot access stored credentials |
| 232 | +
|
| 233 | +### API Key Management |
| 234 | +- **Unique Per Session:** Each authentication generates new API key |
| 235 | +- **Server-Side Validation:** All API keys validated server-side |
| 236 | +- **Proper Logout:** Server-side session invalidation on logout |
| 237 | +
|
| 238 | +## Development and Testing |
| 239 | +
|
| 240 | +### Testing with Local Login Server |
| 241 | +
|
| 242 | +For testing desktop authentication with a local account server: |
| 243 | +
|
| 244 | +1. **Configure Account URL:** |
| 245 | + - Edit `src/config.json` |
| 246 | + - Change `account_url` from `https://account.phcode.dev/` to `http://localhost:5000/` (or your local server URL) |
| 247 | +
|
| 248 | +2. **Rebuild Application:** |
| 249 | + ```bash |
| 250 | + npm run build |
| 251 | + ``` |
| 252 | +
|
| 253 | +3. **Start Your Local Account Server:** |
| 254 | + - Ensure your local account server is running on the configured port (e.g., localhost:5000) |
| 255 | + - Verify all authentication endpoints are properly configured |
| 256 | +
|
| 257 | +4. **Test Desktop Authentication:** |
| 258 | + - Desktop app will now use your local server for all authentication calls |
| 259 | + - Verification codes and API key resolution will go through your local server |
| 260 | + - Auto-verification will attempt to connect to your local account service |
| 261 | +
|
| 262 | +**Note:** Unlike browser testing which requires proxy server configuration, desktop apps simply use the `account_url` directly from config.json. |
| 263 | +
|
| 264 | +## Troubleshooting |
| 265 | +
|
| 266 | +### Common Issues |
| 267 | +
|
| 268 | +**1. "No savedUserProfile found" errors:** |
| 269 | +- Check if Kernel Mode Trust is properly initialized |
| 270 | +- Verify Tauri keychain access permissions |
| 271 | +- Ensure credentials weren't cleared by system security policies |
| 272 | + |
| 273 | +**2. Verification code timeout:** |
| 274 | +- Verification codes expire after 5 minutes |
| 275 | +- User must restart login process if expired |
| 276 | +- Check local Node.js server connectivity for auto-verification |
| 277 | + |
| 278 | +**3. Auto-verification fails:** |
| 279 | +- **Safari Browser:** Auto-verification is blocked by Safari's security policies |
| 280 | +- **Firewall:** May be blocking localhost communication |
| 281 | +- **Local Server Issues:** Server may not be running properly |
| 282 | +- **Solution:** Always fall back to manual verification code entry |
| 283 | +
|
| 284 | +**4. API key validation failures:** |
| 285 | +- Check network connectivity to account service |
| 286 | +- Verify API key hasn't been invalidated server-side |
| 287 | +- Confirm account service URL configuration |
| 288 | + |
| 289 | +### Development Tips |
| 290 | + |
| 291 | +1. **Monitor Kernel Mode Trust Access:** Ensure proper initialization and access patterns |
| 292 | +2. **Test Auto-Verification Flow:** |
| 293 | + - Test in Chrome/Firefox for full functionality |
| 294 | + - Test in Safari to ensure graceful fallback to manual entry |
| 295 | + - Verify localhost server starts and responds correctly |
| 296 | +3. **Browser Testing Strategy:** |
| 297 | + - Chrome/Firefox: Expect auto-verification to work |
| 298 | + - Safari: Always expect manual verification flow |
| 299 | + - Test user experience in both scenarios |
| 300 | +4. **Validate Credential Storage:** Check system keychain directly if available |
| 301 | +5. **Test Multi-Window Sync:** Verify login state propagates across application windows |
| 302 | +6. **Security Testing:** Test phishing protection by attempting malicious URL scenarios |
| 303 | + |
| 304 | +## API Error Handling |
| 305 | + |
| 306 | +### Error Codes |
| 307 | +```javascript |
| 308 | +const ERR_RETRY_LATER = "retry_later"; // Network/temporary errors |
| 309 | +const ERR_INVALID = "invalid"; // API key/verification code invalid |
| 310 | +``` |
| 311 | + |
| 312 | +### Response Handling |
| 313 | +```javascript |
| 314 | +const resolveResponse = await _resolveAPIKey(apiKey, validationCode); |
| 315 | +if(resolveResponse.userDetails) { |
| 316 | + // Success: use userDetails |
| 317 | +} else if(resolveResponse.err === ERR_INVALID) { |
| 318 | + // Invalid credentials: force re-authentication |
| 319 | + await _resetAccountLogin(); |
| 320 | +} else if(resolveResponse.err === ERR_RETRY_LATER) { |
| 321 | + // Temporary error: retry later |
| 322 | +} |
| 323 | +``` |
| 324 | + |
| 325 | +--- |
| 326 | + |
| 327 | +For desktop implementation details, see the source code in `src/services/login-desktop.js`. For browser authentication, see `src/services/login-browser.js` and `readme-login-browser-no_dist.md`. |
| 328 | + |
| 329 | +For deeper understanding of the Kernel Mode Trust security architecture and secure credential storage implementation, refer to the Kernel Mode Trust source files (out of scope for this document). |
0 commit comments