ilteris kaplan blog

Building and Debugging the 'Ah-Ha! Capture' Chrome Extension: A Summary

May 24, 2025

I. Planning & Initial Setup:

  1. Initial Task: Build a Chrome extension to capture information from websites.
  2. Planning Phase:

    • Recognized the need for a detailed plan before coding, especially considering backend integration, OAuth, etc.
    • Used the sequential-thinking MCP tool to create a comprehensive development plan, covering:

      • Core functionalities (snippet extraction).
      • UI/UX (popup, context menu, auth flow).
      • Technical architecture (manifest, background/content scripts, storage).
      • API interactions and security.
      • Phased development approach.
      • Testing strategy.
    • Wrote this plan to AH_HA_CHROME_EXTENSION_PLAN.md.
  3. Mode Switch: Switched from “Architect” to “Code” mode to begin implementation.
  4. Basic File Structure & Manifest:

    • Created the ah-ha-chrome-extension directory.
    • Created manifest.json defining version 3, name, description, initial permissions (activeTab, storage, scripting, contextMenus), popup, icons, background service worker, and content script.
  5. Popup UI Skeleton:

  6. Core Scripts:

  7. Placeholder Icons: Confirmed user added placeholder icons to ah-ha-chrome-extension/icons/.

II. Implementing Authentication (OAuth 2.0 with Google):

  1. Refined Popup-Background Communication:

    • Updated popup.js to send GET_AUTH_STATUS, LOGIN, LOGOUT messages to background.js.
    • Updated background.js to handle these messages, initially with simulated auth logic using chrome.storage.local for an ahHaUserLoggedIn flag.
  2. OAuth Flow Implementation (background.js):

    • Added the identity permission to manifest.json.
    • Defined OAuth 2.0 configuration constants (Client ID, Auth URL, Scopes, Redirect URI). User updated these with actual Google provider details.
    • Implemented initiateOAuthFlow using chrome.identity.launchWebAuthFlow.
    • Modified the LOGIN message handler to call initiateOAuthFlow.
  3. Token Extraction & Storage (background.js):

    • Updated initiateOAuthFlow’s callback to parse the redirect URL from Google to extract access_token, id_token, and expires_in.
    • Stored these tokens (and ahHaUserLoggedIn: true) in chrome.storage.local.
  4. Nonce Implementation for OIDC Security (background.js):

    • Addressed Google’s “Nonce required” error.
    • Generated a unique nonce before launchWebAuthFlow.
    • Stored the nonce in chrome.storage.local.
    • Added the nonce to the authentication request URL.
    • Implemented basic JWT parsing (parseJwt function) to extract the nonce from the returned id_token.
    • Verified the received nonce against the stored nonce.
    • Ensured the stored oauthNonce is cleared after the flow.
  5. Debugging Auth State Synchronization:

    • Addressed an issue where the auth state (tokens in storage, in-memory flags) wasn’t consistently updated or read immediately after login, leading to “User not authenticated” errors during snippet saving.
    • Introduced in-memory variables (currentAuthToken, currentUserLoggedIn) in background.js.
    • Refined checkAuthenticationStatus to prioritize in-memory state, then fall back to chrome.storage.local, and to update in-memory state from storage if necessary.
    • Ensured the initiateOAuthFlow callback updates in-memory variables after chrome.storage.local.set successfully completes (using its callback).
    • Added extensive logging to trace state changes and storage operations, which was crucial for diagnosing the timing/asynchronicity issues.

III. Implementing Snippet Saving & Backend Integration:

  1. Backend Endpoint Correction:

    • Identified a 404 Not Found error because the extension was calling /api/v1/snippets, but the FastAPI backend (ah-ha-backend/main.py) had the route defined as /ah-has/.
    • Corrected the route in ah-ha-backend/main.py to @app.post("/api/v1/snippets", ...).
  2. Backend Dependency Management:

    • Addressed Pylance import errors (uvicorn, fastapi, pydantic) by creating ah-ha-backend/requirements.txt and guiding the user to install dependencies into their virtual environment and set the VS Code Python interpreter.
  3. Backend Payload Validation (422 Error):

    • Diagnosed a 422 Unprocessable Entity error: the backend’s AhHaSnippet Pydantic model required a title, but the extension wasn’t sending one.
    • Modified ah-ha-chrome-extension/background.js (within saveSnippet) to include a default title (first 70 chars of content) in the payload sent to the backend.
  4. Using Real Auth Token for API Calls (background.js):

    • Updated the saveSnippet function to retrieve the stored authToken from chrome.storage.local (and prioritize the in-memory currentAuthToken) and include it in the Authorization: Bearer <token> header of the API request.
    • Added basic token expiry checks and 401 error handling.
  5. Backend Port Correction:

IV. Implementing Pre-Save Enrichment UI:

  1. Capture UI Creation:

    • Created capture_ui/capture.html with form fields for title, content, and tags.
    • Created capture_ui/capture.css for styling.
    • Created capture_ui/capture.js to:

      • Receive initial data (selected text, URL, auto-title) via URL parameters.
      • Populate the form.
      • Send enriched data (edited title, content, tags, URL) back to background.js via a SAVE_ENRICHED_SNIPPET message.
      • Handle save/cancel actions.
  2. Modifying Context Menu Flow (background.js):

    • Updated handleContextMenuClick to open capture_ui/capture.html in a new window, passing initial data as URL parameters.
    • Added a message listener for SAVE_ENRICHED_SNIPPET to receive data from the capture UI and then call saveSnippet.

V. User Feedback (Notifications):

  1. Enhanced Save Confirmation:

    • Added the "notifications" permission to manifest.json.
    • Updated the chrome.notifications.create call in background.js (for successful saves via SAVE_ENRICHED_SNIPPET) to include priority: 2 and requireInteraction: true to make the success notification more prominent.

Throughout this process, we iteratively tested, examined logs, diagnosed issues, and applied fixes to both the extension and (by instruction) the backend configuration.


Written by Ilteris Kaplan who still lives and works in New York. Twitter