Skip to content

Commit 115e8ba

Browse files
committed
bump version to 0.1.7
1 parent 607482f commit 115e8ba

File tree

1 file changed

+271
-0
lines changed

1 file changed

+271
-0
lines changed

plan.md

Lines changed: 271 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,271 @@
1+
# OAuth Authentication Implementation Plan
2+
3+
This document outlines the phased implementation plan for replacing API key authentication with OAuth in the Array app.
4+
5+
## Overview
6+
7+
- **Goal**: Replace manual API key entry with "Sign in with PostHog" OAuth flow
8+
- **Strategy**: OAuth only (remove API key option)
9+
- **Callback**: Localhost HTTP server on port 8239 (same as CLI)
10+
- **Regions**: Support US/EU/Dev with region selector
11+
- **Token Refresh**: Proactive background refresh + reactive 401 handling + refresh token rotation
12+
13+
## Stage 1: Core OAuth Infrastructure
14+
15+
**PR 1: Add OAuth service and IPC handlers**
16+
17+
### Files to Create:
18+
- `src/shared/constants/oauth.ts` - OAuth constants (client IDs, port, scopes)
19+
- `src/shared/types/oauth.ts` - TypeScript types (CloudRegion, OAuthTokenResponse, etc.)
20+
- `src/main/services/oauth.ts` - OAuth service with PKCE flow
21+
22+
### Files to Modify:
23+
- `src/main/index.ts` - Register OAuth IPC handlers
24+
- `src/main/preload.ts` - Add OAuth IPC type definitions
25+
26+
### Implementation Details:
27+
1. **OAuth Constants** (`src/shared/constants/oauth.ts`)
28+
- Client IDs: `POSTHOG_US_CLIENT_ID`, `POSTHOG_EU_CLIENT_ID`, `POSTHOG_DEV_CLIENT_ID`
29+
- `OAUTH_PORT = 8239`
30+
- OAuth scopes array
31+
- Helper functions: `getCloudUrlFromRegion()`, `getOauthClientIdFromRegion()`
32+
33+
2. **OAuth Types** (`src/shared/types/oauth.ts`)
34+
- `CloudRegion`: 'us' | 'eu' | 'dev'
35+
- `OAuthTokenResponse`: access_token, refresh_token, expires_in, etc.
36+
- `OAuthConfig`: scopes, cloudRegion
37+
38+
3. **OAuth Service** (`src/main/services/oauth.ts`)
39+
- PKCE functions: `generateCodeVerifier()`, `generateCodeChallenge()`
40+
- `startCallbackServer()` - HTTP server handling `/authorize` and `/callback`
41+
- `exchangeCodeForToken()` - Code exchange with PostHog
42+
- `performOAuthFlow()` - Main orchestration function
43+
- Token encryption using `safeStorage`
44+
- IPC handlers: `startOAuthFlow`, `storeOAuthTokens`, `retrieveOAuthTokens`, `deleteOAuthTokens`, `refreshOAuthToken`
45+
46+
4. **IPC Registration** (`src/main/index.ts`)
47+
- Import OAuth handlers
48+
- Register on app initialization
49+
50+
5. **Preload Types** (`src/main/preload.ts`)
51+
- Add OAuth methods to `electronAPI` interface
52+
- Type-safe IPC bridge for renderer
53+
54+
### Testing:
55+
- Verify OAuth server starts on port 8239
56+
- Test PKCE code generation
57+
- Verify token encryption/decryption
58+
- Test IPC communication between renderer and main
59+
60+
---
61+
62+
## Stage 2: State Management & Token Refresh
63+
64+
**PR 2: Refactor authStore and add token refresh logic**
65+
66+
### Files to Modify:
67+
- `src/renderer/features/auth/stores/authStore.ts` - Refactor for OAuth state
68+
- `src/api/fetcher.ts` - Add OAuth token and 401 handling
69+
- `src/api/posthogClient.ts` - Update constructor for OAuth
70+
71+
### Implementation Details:
72+
73+
1. **AuthStore Refactor** (`authStore.ts`)
74+
- **Remove**: `apiKey`, `encryptedKey`, `openaiApiKey`, `encryptedOpenaiKey`
75+
- **Add**:
76+
- `oauthAccessToken: string | null`
77+
- `oauthRefreshToken: string | null`
78+
- `tokenExpiry: number | null` (Unix timestamp)
79+
- `cloudRegion: CloudRegion | null`
80+
- **Methods**:
81+
- `loginWithOAuth(region: CloudRegion)` - Calls IPC to start OAuth flow
82+
- `refreshAccessToken()` - Refresh token logic with rotation handling
83+
- `scheduleTokenRefresh()` - Proactive refresh 5 mins before expiry
84+
- `initializeOAuth()` - Restore session on app launch
85+
- `logout()` - Clear OAuth tokens
86+
87+
2. **Token Refresh Logic**:
88+
- Proactive: `setTimeout` scheduled refresh (expires_in - 5min)
89+
- Reactive: 401 interceptor in fetcher
90+
- Handle refresh token rotation (update both tokens)
91+
- On refresh failure: logout and show AuthScreen
92+
93+
3. **API Fetcher Update** (`fetcher.ts`)
94+
- Change `Authorization` header to use OAuth access token
95+
- Add response interceptor:
96+
```typescript
97+
if (response.status === 401) {
98+
await authStore.getState().refreshAccessToken();
99+
// Retry original request
100+
}
101+
```
102+
- Remove API key logic
103+
104+
4. **PostHog Client Update** (`posthogClient.ts`)
105+
- Constructor takes `accessToken` and `apiHost`
106+
- Derive `apiHost` from `cloudRegion`
107+
108+
### Testing:
109+
- Test token refresh on 401 response
110+
- Test proactive token refresh
111+
- Test refresh token rotation
112+
- Test logout clears all OAuth state
113+
114+
---
115+
116+
## Stage 3: UI Updates
117+
118+
**PR 3: Update AuthScreen and SettingsView for OAuth**
119+
120+
### Files to Modify:
121+
- `src/renderer/features/auth/components/AuthScreen.tsx` - OAuth UI
122+
- `src/renderer/features/settings/components/SettingsView.tsx` - OAuth status display
123+
- `src/renderer/App.tsx` - Update auth initialization
124+
125+
### Implementation Details:
126+
127+
1. **AuthScreen Redesign** (`AuthScreen.tsx`)
128+
- **Add**: Region selector (RadioGroup with US/EU/Dev options)
129+
- **Replace**: API key form with "Sign in with PostHog" button
130+
- **Add**: Loading state ("Waiting for authorization...")
131+
- **Add**: Error state handling (timeout, access denied, etc.)
132+
- **Remove**: API key TextField, custom host TextField
133+
- Layout: Keep two-pane design, left side has region selector + button
134+
135+
2. **SettingsView Update** (`SettingsView.tsx`)
136+
- **Show**: OAuth connection status
137+
- Region badge (US/EU/Dev)
138+
- Connected account email (if available from token)
139+
- **Add**: "Re-authenticate" button
140+
- **Update**: "Sign out" button (calls OAuth logout)
141+
- **Remove**: API key display/edit fields
142+
143+
3. **App.tsx Update**
144+
- Call `authStore.initializeOAuth()` on mount
145+
- Handle token expiry edge cases
146+
147+
### Testing:
148+
- Test OAuth flow from AuthScreen
149+
- Test region switching
150+
- Test error states (timeout, denial)
151+
- Test re-authentication from Settings
152+
- Test logout flow
153+
154+
---
155+
156+
## Stage 4: Cleanup & Polish
157+
158+
**PR 4: Remove API key code and final cleanup**
159+
160+
### Files to Modify:
161+
- `src/main/services/posthog.ts` - Remove API key IPC handlers
162+
- Clean up any unused imports/types
163+
164+
### Implementation Details:
165+
166+
1. **Remove API Key Code**:
167+
- Delete `storeApiKey`, `retrieveApiKey` IPC handlers
168+
- Remove API key encryption logic (if not used elsewhere)
169+
- Clean up unused imports
170+
171+
2. **Migration Considerations**:
172+
- Old encrypted API keys in localStorage will be orphaned (acceptable)
173+
- Users will need to re-authenticate with OAuth
174+
175+
3. **Documentation**:
176+
- Update README if it mentions API keys
177+
- Add OAuth setup instructions
178+
179+
### Testing:
180+
- Full end-to-end OAuth flow for all regions
181+
- Test app launch with existing OAuth session
182+
- Test app launch without session (shows AuthScreen)
183+
- Test token refresh scenarios
184+
- Test logout and re-authentication
185+
186+
---
187+
188+
## OAuth Flow Sequence
189+
190+
```
191+
1. User selects region (US/EU/Dev)
192+
193+
2. User clicks "Sign in with PostHog"
194+
195+
3. Renderer calls IPC: startOAuthFlow(region)
196+
197+
4. Main process starts HTTP server on localhost:8239
198+
199+
5. Main process opens browser to localhost:8239/authorize
200+
201+
6. Browser redirects to PostHog OAuth page (with PKCE challenge)
202+
203+
7. User authorizes on PostHog
204+
205+
8. PostHog redirects to localhost:8239/callback?code=...
206+
207+
9. Callback server receives code
208+
209+
10. Main process exchanges code for tokens
210+
211+
11. Main process encrypts tokens
212+
213+
12. Main process returns tokens to renderer via IPC
214+
215+
13. Renderer updates authStore
216+
217+
14. Renderer creates PostHog client with access token
218+
219+
15. Schedule proactive token refresh
220+
221+
16. Authenticated! 🎉
222+
```
223+
224+
## Token Refresh Flow
225+
226+
```
227+
Proactive Refresh (every ~55 mins for 60-min tokens):
228+
- setTimeout scheduled on login/refresh
229+
- Calls refresh endpoint 5 mins before expiry
230+
- Updates both access + refresh tokens
231+
- Reschedules next refresh
232+
233+
Reactive Refresh (on 401):
234+
- API request returns 401
235+
- Interceptor calls refreshAccessToken()
236+
- Retries original request with new token
237+
- If refresh fails: logout user
238+
```
239+
240+
## Key Dependencies
241+
242+
- `crypto` (Node.js) - PKCE code generation
243+
- `http` (Node.js) - Callback server
244+
- `electron.safeStorage` - Token encryption
245+
- `open` or `electron.shell.openExternal` - Browser opening
246+
247+
## Environment Variables
248+
249+
Consider adding to `.env` (optional):
250+
```bash
251+
POSTHOG_OAUTH_CLIENT_ID_US=c4Rdw8DIxgtQfA80IiSnGKlNX8QN00cFWF00QQhM
252+
POSTHOG_OAUTH_CLIENT_ID_EU=bx2C5sZRN03TkdjraCcetvQFPGH6N2Y9vRLkcKEy
253+
POSTHOG_OAUTH_CLIENT_ID_DEV=DC5uRLVbGI02YQ82grxgnK6Qn12SXWpCqdPb60oZ
254+
```
255+
256+
## Testing Checklist
257+
258+
- [x] OAuth flow completes successfully for US region
259+
- [x] OAuth flow completes successfully for EU region
260+
- [x] OAuth flow completes successfully for Dev region
261+
- [x] Proactive token refresh works
262+
- [x] Reactive token refresh works on 401
263+
- [x] Refresh token rotation updates both tokens
264+
- [x] Logout clears all OAuth state
265+
- [x] App restart with valid tokens restores session
266+
- [x] App restart without tokens shows AuthScreen
267+
- [x] Timeout handling (60s limit)
268+
- [x] User denies access handling
269+
- [x] Port 8239 conflict handling
270+
- [ ] Network error handling
271+
- [ ] Token expiry edge cases

0 commit comments

Comments
 (0)