All skills
clerk avatar

/clerk-chrome-extension-patterns

@792a318 official
by clerkclerk/skills83 stars
5

Chrome Extension auth with @clerk/chrome-extension -- popup/sidepanel setup, syncHost for OAuth/SAML via web app, createClerkClient for service workers and headless extensions, stable CRX ID. Triggers on: Chrome extension auth, Plasmo clerk, popup sign-in, syncHost, background service worker token, createClerkClient, headless extension.

Use this Skill: https://skilld.dev/gh/clerk/skills/clerk-chrome-extension-patterns

This session only. Nothing lands on disk.

referencessync-host.md

≈1.1k tokens on demand. Your agent reads this file only when SKILL.md points to it.

syncHost -- Sync Auth with Web App

When to Use

Use syncHost when you need:

  • OAuth (Google, GitHub, etc.)
  • SAML
  • Email magic links
  • The extension to reflect auth state from your web app without the user signing in again

Without syncHost, the extension popup can only do email/password, OTP, and passkeys.

How It Works

The extension reads Clerk's session cookie from your web app's domain using host_permissions. The syncHost prop tells ClerkProvider which domain to sync from.

Step 1 -- Environment Variables

Use separate files for dev vs prod so Plasmo passes the right values to each build.

.env.development:

PLASMO_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_...
CLERK_FRONTEND_API=https://your-app.clerk.accounts.dev
PLASMO_PUBLIC_CLERK_SYNC_HOST=http://localhost

.env.production:

PLASMO_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_live_...
CLERK_FRONTEND_API=https://clerk.your-domain.com
PLASMO_PUBLIC_CLERK_SYNC_HOST=https://clerk.your-domain.com

The production value of PLASMO_PUBLIC_CLERK_SYNC_HOST is the domain your Clerk Frontend API runs on (e.g., https://clerk.your-domain.com), not your app's main domain.

Step 2 -- ClerkProvider with syncHost

import { ClerkProvider, Show, UserButton } from '@clerk/chrome-extension'
import { Link, Outlet, useNavigate } from 'react-router-dom'

const PUBLISHABLE_KEY = process.env.PLASMO_PUBLIC_CLERK_PUBLISHABLE_KEY
const SYNC_HOST = process.env.PLASMO_PUBLIC_CLERK_SYNC_HOST

if (!PUBLISHABLE_KEY || !SYNC_HOST) {
  throw new Error('Missing PLASMO_PUBLIC_CLERK_PUBLISHABLE_KEY or PLASMO_PUBLIC_CLERK_SYNC_HOST')
}

export function RootLayout() {
  const navigate = useNavigate()

  return (
    <ClerkProvider
      publishableKey={PUBLISHABLE_KEY}
      syncHost={SYNC_HOST}
      afterSignOutUrl="/"
      routerPush={(to) => navigate(to)}
      routerReplace={(to) => navigate(to, { replace: true })}
    >
      <Outlet />
    </ClerkProvider>
  )
}

Step 3 -- Manifest host_permissions

In package.json, configure host_permissions to grant the extension access to the sync host domain:

{
  "manifest": {
    "key": "$CRX_PUBLIC_KEY",
    "permissions": ["cookies", "storage"],
    "host_permissions": [
      "$PLASMO_PUBLIC_CLERK_SYNC_HOST/*",
      "$CLERK_FRONTEND_API/*"
    ]
  }
}

Plasmo interpolates env vars in package.json at build time. In dev this resolves to http://localhost/*.

Step 4 -- Register Extension ID in Clerk

Clerk must explicitly allow requests from the extension's origin. Run this once per environment:

curl -X PATCH https://api.clerk.com/v1/instance \
  -H "Authorization: Bearer YOUR_SECRET_KEY" \
  -H "Content-type: application/json" \
  -d '{"allowed_origins": ["chrome-extension://YOUR_EXTENSION_ID"]}'

Replace YOUR_SECRET_KEY with your Clerk Secret Key (sk_test_... or sk_live_...) and YOUR_EXTENSION_ID with your stable CRX ID.

If your extension ID changes (unstable key), you must re-run this command. Configure a stable CRX ID to avoid repeating this step.

Hide Unsupported Auth Methods in Popup

When using syncHost, your web app may have OAuth enabled but the popup itself can't do OAuth flows. Hide those buttons in the popup:

import { SignIn, SignUp } from '@clerk/chrome-extension'

function SignInPage() {
  return (
    <SignIn
      appearance={{
        elements: {
          socialButtonsRoot: 'plasmo-hidden',
          dividerRow: 'plasmo-hidden',
        },
      }}
    />
  )
}

function SignUpPage() {
  return (
    <SignUp
      appearance={{
        elements: {
          socialButtonsRoot: 'plasmo-hidden',
          dividerRow: 'plasmo-hidden',
        },
      }}
    />
  )
}

This way the popup shows only the methods it supports (email/password, OTP) while the web app exposes all methods including OAuth.

Side Panel Limitation

syncHost does not fully support side panels. If a user signs in via the web app, the side panel will not automatically update its auth state. The user must close and reopen the side panel to reflect the new auth status. This is a known limitation of the SDK.

Docs

Sync auth status guide

Source: SKILL.md on GitHub

1 alert15d4 checks · Risk CRITICAL
  • Gen Agent Trust Hub16d

    The skill is safe. It provides reference documentation and template files for implementing Clerk authentication within Chrome Extensions using the Plasmo framework. The URL flagged by the automated scanner is a standard, benign placeholder domain commonly used in developer documentation to represent a custom user domain.

  • Socket15d

    1 alert: gptAnomaly

  • Snyk16d

    Risk: LOW · No issues

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at 792a318. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub yesterday.

Activeupdated 6 months ago
What it can do
Network
All 1 allowed tools
WebFetch
Other metadata
compatibility
Requires PLASMO_PUBLIC_CLERK_PUBLISHABLE_KEY (Plasmo prefix for public env vars) and CLERK_FRONTEND_API.
metadata
{
  "author": "clerk",
  "version": "2.0.0",
  "references": [
    "references/sync-host.md",
    "references/create-clerk-client.md",
    "references/content-scripts.md",
    "references/headless-extension.md"
  ]
}
  • clerk
  • chrome-extension
  • authentication
  • plasmo
  • oauth
  • saml
  • passkeys
  • service-worker
  • popup
  • sidepanel

README badge

README badge for clerk/skills/clerk-chrome-extension-patterns

Guides Chrome extension authentication with Clerk's `@clerk/chrome-extension` library, covering popup/side panel setup, OAuth delegation via syncHost to a web app, service worker token management with createClerkClient, and stable extension ID configuration. Targets Plasmo-based extensions and addresses the specific constraints of extension environments — email links don't work in popups, OAuth requires web app delegation, and bot protection must be disabled.

Generated from the current SKILL.md.

Does this skill support OAuth and SAML in Chrome extension popups?
No. OAuth (Google, GitHub, etc.) and SAML are not supported in popups or side panels. Use syncHost to delegate authentication to your web app instead.
Can I use Clerk React hooks in service workers and content scripts?
No. Service workers and content scripts have no access to Clerk React hooks. Use createClerkClient() for service workers or message passing from content scripts to the background service worker.
What happens to my extension ID when I rebuild?
Without a stable CRX ID configured via a pinned key in manifest, Chrome generates a new ID on each rebuild, breaking your allowed origins. Configure a stable key using Plasmo Itero before deploying.
How do I sync authentication between my Chrome extension and web app?
Use syncHost to read the Clerk session cookie from your web app's domain. Configure host_permissions for both the sync host and Clerk API, then add your extension ID to Clerk's allowed origins via the API.
Do email magic links work in Chrome extension popups?
No. Magic link sign-in does not work in popups because the popup closes when the user clicks outside, resetting sign-in state. Use email OTP, password, passkeys, or delegate to your web app via syncHost instead.

Generated from the current SKILL.md. These answers refresh after source changes.