Skip to content
Supastack
EN
Theme
Sign inGet lifetime access
All articles

How to Build a SaaS with a Companion Chrome Extension (MV3) Sharing Web Auth & API

Most teams build a second backend for their browser extension. Here's how to ship a Manifest V3 companion that talks to your existing SaaS through workspace API keys — no duplicate auth, no second database.

Noah Zixin Zhang3 min read

How do you build a Chrome extension that shares your SaaS backend?

It depends on not building a second backend. MV3 extensions can't rely on HttpOnly cookies, so authenticate with workspace API keys instead: the extension calls your app's versioned REST API (/api/v1) with a scoped key bound to one workspace, reusing the same auth model, tenant scoping, and Postgres database as the web app. supastack ships an MV3 scaffold — popup, options page, background worker, least-privilege manifest — wired exactly this way.

The Trap: Accidentally Building a Second Backend

The usual story: your SaaS needs a companion extension to capture pages, clip content or annotate the web. Six months later you maintain two auth systems (cookies for web, something hand-rolled for the extension), a parallel API the extension can actually call, and a sync layer reconciling two data stores that were supposed to be one.

None of that is necessary. An extension is a client of your existing product — it needs a credential it can hold, an API meant for programmatic access, and nothing else. The mistake is reaching for a new backend instead of the workspace API keys and versioned REST surface a serious SaaS already has.

What Manifest V3 Actually Lets You Do

MV3 replaced background pages with ephemeral service workers and pushed extensions toward least-privilege permissions. Practically: you cannot lean on persistent in-memory state, you should not scrape cookies for session reuse (HttpOnly cookies are unreachable anyway), and every host permission is a Web Store review question.

The clean answer is the one the platform already gives you: a scoped credential in chrome.storage.local and HTTPS calls to your app's origin, requested as an optional host permission at setup time — not install time.

The supastack MV3 Scaffold: What's Already Wired

supastack's apps/extension is a deliberately small, framework-free Manifest V3 companion — 'Save page to workspace' — that demonstrates the whole pattern end to end. It captures the active tab's title, URL and selected text into a workspace content entry through the versioned REST API, POST /api/v1/content-entries.

Authentication is a workspace API key (sk_…) created under Settings → Developers: the key is bound to exactly one workspace, so the binding is the workspace selection — the key can never write outside it. The options page stores the app URL and key in chrome.storage.local, requests access to that origin only, and verifies the connection through GET /api/v1/workspaces/current.

apps/extension/
  manifest.json        MV3: service worker, least-privilege permissions
  src/
    background.js      context-menu save + badge feedback
    popup.html/.js     capture UI — title, URL, selection, note
    options.html/.js   app URL + workspace API key setup
    lib/
      api.mjs          versioned /api/v1 client (key auth)
      capture.mjs      active-tab + selection capture
      config.mjs       chrome.storage.local persistence

Least-Privilege by Default

The scaffold ships with the smallest permission set the job needs — which matters for Web Store review and for user trust:

  • No tabs, no <all_urls>, no cookies/webRequest/declarativeNetRequest — the scaffold is honest about what it doesn't need.
PermissionWhy it's there
activeTabRead the current page's title/URL only when invoked
scriptingRead the text selection inside the invoked tab
contextMenusRegister the right-click save action
storagePersist app URL, API key, cached workspace
optional_host_permissionsApp origin requested at setup, never at install — zero site access on install

From Scaffold to Your Product's Companion

Rebranding is renaming manifest.json; extending is the interesting part, and it stays inside the same pattern — new capture types call new /api/v1 endpoints with the same key, and the typed @supastack/api-sdk generated from the app's OpenAPI document keeps request shapes honest.

Because the extension reads and writes through the same tenant-scoped API as every other client, a saved page lands in the same Postgres rows the web dashboard lists — one database, one auth model, one place where workspaceId scoping is enforced. No second backend, no sync, no drift. Compare tiers on the pricing page.

DIY second-backend approachsupastack MV3 scaffold
AuthHand-rolled token system beside cookiesWorkspace API keys — same auth model as web
APINew endpoints invented for the extensionVersioned /api/v1 + OpenAPI-typed SDK
DataSecond store + sync logicSame Postgres rows, workspace-scoped
PermissionsBroad access for convenienceLeast-privilege manifest, review-friendly

FAQ: SaaS + Chrome Extension on One Backend

What developers ask before shipping an extension companion:

  • Why API keys instead of the user's session cookie?, HttpOnly cookies are invisible to extension JS by design, and MV3 service workers are ephemeral — a scoped sk_… key in chrome.storage.local is durable, revocable, and bound to one workspace so it can never cross tenants.
  • Does the extension work in Firefox too?, MV3 supports the same surface; the code uses a browser ?? chrome namespace shim and is developed Chromium-first, so Firefox is a port, not a rewrite.
  • Is it store-ready out of the box?, It's a production-pattern scaffold, not a store submission — you'll rebrand the manifest, add your own capture logic, and write the listing. The hard part (auth, API, tenant scoping) is already done.
  • Which license includes the extension?, The Full Bundle at $299 ships all five surfaces — two web engines, Expo, Tauri and the extension scaffold — in one repo.

Your next product starts here.

Pay once. Keep building profitable products.