Files
2026-01-10 00:04:52 +01:00

8.0 KiB

CHANGELOG: GIT-004A Phase 5B - Web OAuth Flow

Overview

Implemented GitHub Web OAuth Flow to replace Device Flow, enabling users to select which organizations and repositories to grant access to during authentication.

Status: FAILED - See FAILURE-REPORT.md

Date Attempted: January 9-10, 2026
Time Spent: ~4 hours
Result: OAuth completes but callback handling broken - debug logs never appear

See detailed failure analysis: FAILURE-REPORT.md


Changes Made

1. Main Process OAuth Handler

File: packages/noodl-editor/src/main/github-oauth-handler.ts (NEW)

  • Created GitHubOAuthCallbackHandler class
  • Implements localhost HTTP server on ports 3000-3004 (with fallback)
  • Handles /github/callback route for OAuth redirects
  • CSRF protection via state parameter
  • Exchanges authorization code for access token
  • Fetches user info and installation data from GitHub API
  • Sends results to renderer process via IPC
  • Beautiful success/error pages for browser callback

Key Features:

  • Port fallback mechanism (tries 3000-3004)
  • Secure state validation (5-minute expiration)
  • Proper error handling with user-friendly messages
  • Clean IPC communication with renderer

2. Main Process Integration

File: packages/noodl-editor/src/main/main.js

  • Imported initializeGitHubOAuthHandlers
  • Registered OAuth handlers in app.on('ready') event
  • IPC channels: github-oauth-start, github-oauth-stop
  • IPC events: github-oauth-complete, github-oauth-error

3. GitHub Auth Service Upgrade

File: packages/noodl-editor/src/editor/src/services/github/GitHubAuth.ts

Added:

  • startWebOAuthFlow() - New Web OAuth implementation
  • Communicates with main process via IPC
  • Opens browser to GitHub authorization page
  • Waits for callback with 5-minute timeout
  • Saves token + installations to storage
  • Proper cleanup of IPC listeners

Deprecated:

  • startDeviceFlow() - Marked as deprecated
  • Now forwards to startWebOAuthFlow() for backward compatibility

Removed Dependencies:

  • No longer depends on @octokit/auth-oauth-device
  • Uses native Electron IPC instead

4. Type Definitions Enhanced

File: packages/noodl-editor/src/editor/src/services/github/GitHubTypes.ts

Added:

  • GitHubInstallation interface
    • Installation ID
    • Account info (login, type, avatar)
    • Repository selection type
    • List of repositories (if selected)

Updated:

  • StoredGitHubAuth interface now includes installations?: GitHubInstallation[]

5. Token Store Enhanced

File: packages/noodl-editor/src/editor/src/services/github/GitHubTokenStore.ts

Updated:

  • saveToken() now accepts optional installations parameter
  • Logs connected organizations when saving
  • Added getInstallations() method to retrieve stored installations

6. UI Updated

File: packages/noodl-editor/src/editor/src/views/panels/VersionControlPanel/components/GitProviderPopout/sections/CredentialsSection.tsx

Changed:

  • handleConnect() now calls GitHubAuth.startWebOAuthFlow() instead of startDeviceFlow()
  • UI flow remains identical for users
  • Progress messages update during OAuth flow
  • Error handling unchanged

Technical Implementation Details

OAuth Flow Sequence

1. User clicks "Connect GitHub Account" button
   ↓
2. Renderer calls GitHubAuth.startWebOAuthFlow()
   ↓
3. Renderer sends IPC 'github-oauth-start' to main process
   ↓
4. Main process starts localhost HTTP server (port 3000-3004)
   ↓
5. Main process generates OAuth state (CSRF token)
   ↓
6. Main process returns authorization URL to renderer
   ↓
7. Renderer opens browser to GitHub OAuth page
   ↓
8. GitHub shows: "Where would you like to install OpenNoodl?"
   → User selects organizations
   → User selects repositories (all or specific)
   → User reviews permissions
   ↓
9. User approves → GitHub redirects to localhost:PORT/github/callback?code=XXX&state=YYY
   ↓
10. Main process validates state (CSRF check)
   ↓
11. Main process exchanges code for access token
   ↓
12. Main process fetches user info from GitHub API
   ↓
13. Main process fetches installation info (orgs/repos)
   ↓
14. Main process sends success to renderer via IPC 'github-oauth-complete'
   ↓
15. Renderer saves token + installations to encrypted storage
   ↓
16. UI shows "Connected as USERNAME"
   ↓
17. Main process closes HTTP server

Security Features

  1. CSRF Protection

    • Random 32-byte state parameter
    • 5-minute expiration window
    • Validated on callback
  2. Secure Token Storage

    • Tokens encrypted via electron-store
    • Installation data included in encrypted storage
    • OS-level encryption (Keychain/Credential Manager)
  3. Localhost Only

    • Server binds to 127.0.0.1 (not 0.0.0.0)
    • Only accepts connections from localhost
    • Server auto-closes after auth complete
  4. Error Handling

    • Timeout after 5 minutes
    • Proper IPC cleanup
    • User-friendly error messages

Backward Compatibility

  • startDeviceFlow() still exists (deprecated)
  • Forwards to startWebOAuthFlow() internally
  • Existing code continues to work
  • PAT authentication unchanged

Benefits

For Users

  1. Better Permission Control

    • Select which organizations to connect
    • Choose all repositories or specific ones
    • Review permissions before granting
  2. No More 403 Errors

    • Proper organization repository access
    • Installations grant correct permissions
    • Works with organization private repos
  3. Professional UX

    • Matches Vercel/VS Code OAuth experience
    • Clean browser-based flow
    • No code copying required

For Developers

  1. Cleaner Implementation

    • No polling required
    • Direct callback handling
    • Standard OAuth 2.0 flow
  2. Installation Metadata

    • Know which orgs/repos user granted access to
    • Can display connection status
    • Future: repo selection in UI
  3. Maintainable

    • Standard patterns
    • Well-documented
    • Proper error handling

Testing Checklist

  • Test OAuth with personal repos
  • Test OAuth with organization repos
  • Test org/repo selection UI on GitHub
  • Verify no 403 errors on org repos
  • Test disconnect and reconnect flows
  • Test PAT authentication (should still work)
  • Test error scenarios (timeout, user denies, etc.)
  • Verify token encryption
  • Test port fallback (3000-3004)
  • Verify installation data is saved

Files Modified

Created

  • packages/noodl-editor/src/main/github-oauth-handler.ts

Modified

  • packages/noodl-editor/src/main/main.js
  • packages/noodl-editor/src/editor/src/services/github/GitHubAuth.ts
  • packages/noodl-editor/src/editor/src/services/github/GitHubTypes.ts
  • packages/noodl-editor/src/editor/src/services/github/GitHubTokenStore.ts
  • packages/noodl-editor/src/editor/src/views/panels/VersionControlPanel/components/GitProviderPopout/sections/CredentialsSection.tsx

Next Steps

Phase 2: UI Enhancement (Future Work)

  • Display connected organizations in UI
  • Show repository count per organization
  • Add "Manage Access" button to update permissions

Phase 3: Cleanup (Future Work)

  • Remove @octokit/auth-oauth-device dependency
  • Deprecate GitHubOAuthService.ts
  • Update documentation

Phase 4: Testing (Required Before Merge)

  • Manual testing with personal account
  • Manual testing with organization account
  • Edge case testing (timeouts, errors, etc.)
  • Cross-platform testing (macOS, Windows)

Notes

  • GitHub App credentials already exist (Iv23lib1WdrimUdyvZui)
  • Client secret stored in environment variable
  • Callback URL registered: http://localhost:3000/github/callback
  • Port range 3000-3004 for fallback
  • Installation data saved but not yet displayed in UI

References