Skip to content

feat(chrome-extension): Create js only create clerk client for extensions#7935

Open
royanger wants to merge 8 commits intomainfrom
roy/create-js-only-createClerkClient-for-extensions
Open

feat(chrome-extension): Create js only create clerk client for extensions#7935
royanger wants to merge 8 commits intomainfrom
roy/create-js-only-createClerkClient-for-extensions

Conversation

@royanger
Copy link
Member

@royanger royanger commented Feb 25, 2026

Description

Customers want to be able to use Clerk in JS-only Chrome Extensions, either when building new or when switching an existing extension to Clerk.

This PR adds the /client import path for using createClerkClient() without React.

import { createClerkClient } from '@clerk/chrome-extension/client';

const publishableKey = process.env.CLERK_PUBLISHABLE_KEY;
if (!publishableKey) {
  throw new Error('Missing CLERK_PUBLISHABLE_KEY in .env');
}

const clerk = createClerkClient({ publishableKey });

This deprecates the previous /background only import:

 * // Before (deprecated):
 * import { createClerkClient } from '@clerk/chrome-extension/background';
 * const clerk = await createClerkClient({ publishableKey: 'pk_...' });
 *
 * // After:
 * import { createClerkClient } from '@clerk/chrome-extension/client';
 * const clerk = await createClerkClient({ publishableKey: 'pk_...', background: true });
 */

This also adds a JS only Chrome Extension playground in playground/browser-extension-js.

The latest snapshot works with the new Chrome Extension JS Quickstart repo

Checklist

  • pnpm test runs as expected.
  • pnpm build runs as expected.
  • (If applicable) JSDoc comments have been added or updated for any package exports
  • (If applicable) Documentation has been updated

Type of change

  • 🐛 Bug fix
  • 🌟 New feature
  • 🔨 Breaking change
  • 📖 Refactoring / dependency upgrade / documentation
  • other:

Summary by CodeRabbit

Release Notes

  • New Features

    • New public export path: createClerkClient from @clerk/chrome-extension/client for improved developer experience
    • Added browser extension JS playground with example implementation
  • Deprecations

    • createClerkClient from @clerk/chrome-extension/background is now deprecated; use the new client export path instead
  • Documentation

    • Updated README with new usage examples and application scenarios

@vercel
Copy link

vercel bot commented Feb 25, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
clerk-js-sandbox Ready Ready Preview, Comment Feb 26, 2026 10:53pm

Request Review

@changeset-bot
Copy link

changeset-bot bot commented Feb 25, 2026

🦋 Changeset detected

Latest commit: 99b151a

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@clerk/chrome-extension Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@royanger royanger changed the title Create js only create clerk client for extensions feat(chrome-extension): Create js only create clerk client for extensions Feb 25, 2026
@royanger
Copy link
Member Author

!snapshot

@clerk-cookie
Copy link
Collaborator

Hey @royanger - the snapshot version command generated the following package versions:

Package Version
@clerk/agent-toolkit 0.3.0-snapshot.v20260226185040
@clerk/astro 3.0.0-snapshot.v20260226185040
@clerk/backend 3.0.0-snapshot.v20260226185040
@clerk/chrome-extension 3.0.0-snapshot.v20260226185040
@clerk/clerk-js 6.0.0-snapshot.v20260226185040
@clerk/dev-cli 1.0.0-snapshot.v20260226185040
@clerk/expo 3.0.0-snapshot.v20260226185040
@clerk/expo-passkeys 1.0.0-snapshot.v20260226185040
@clerk/express 2.0.0-snapshot.v20260226185040
@clerk/fastify 2.7.0-snapshot.v20260226185040
@clerk/localizations 4.0.0-snapshot.v20260226185040
@clerk/msw 0.0.1-snapshot.v20260226185040
@clerk/nextjs 7.0.0-snapshot.v20260226185040
@clerk/nuxt 2.0.0-snapshot.v20260226185040
@clerk/react 6.0.0-snapshot.v20260226185040
@clerk/react-router 3.0.0-snapshot.v20260226185040
@clerk/shared 4.0.0-snapshot.v20260226185040
@clerk/tanstack-react-start 1.0.0-snapshot.v20260226185040
@clerk/testing 2.0.0-snapshot.v20260226185040
@clerk/ui 1.0.0-snapshot.v20260226185040
@clerk/upgrade 2.0.0-snapshot.v20260226185040
@clerk/vue 2.0.0-snapshot.v20260226185040

Tip: Use the snippet copy button below to quickly install the required packages.
@clerk/agent-toolkit

npm i @clerk/agent-toolkit@0.3.0-snapshot.v20260226185040 --save-exact

@clerk/astro

npm i @clerk/astro@3.0.0-snapshot.v20260226185040 --save-exact

@clerk/backend

npm i @clerk/backend@3.0.0-snapshot.v20260226185040 --save-exact

@clerk/chrome-extension

npm i @clerk/chrome-extension@3.0.0-snapshot.v20260226185040 --save-exact

@clerk/clerk-js

npm i @clerk/clerk-js@6.0.0-snapshot.v20260226185040 --save-exact

@clerk/dev-cli

npm i @clerk/dev-cli@1.0.0-snapshot.v20260226185040 --save-exact

@clerk/expo

npm i @clerk/expo@3.0.0-snapshot.v20260226185040 --save-exact

@clerk/expo-passkeys

npm i @clerk/expo-passkeys@1.0.0-snapshot.v20260226185040 --save-exact

@clerk/express

npm i @clerk/express@2.0.0-snapshot.v20260226185040 --save-exact

@clerk/fastify

npm i @clerk/fastify@2.7.0-snapshot.v20260226185040 --save-exact

@clerk/localizations

npm i @clerk/localizations@4.0.0-snapshot.v20260226185040 --save-exact

@clerk/msw

npm i @clerk/msw@0.0.1-snapshot.v20260226185040 --save-exact

@clerk/nextjs

npm i @clerk/nextjs@7.0.0-snapshot.v20260226185040 --save-exact

@clerk/nuxt

npm i @clerk/nuxt@2.0.0-snapshot.v20260226185040 --save-exact

@clerk/react

npm i @clerk/react@6.0.0-snapshot.v20260226185040 --save-exact

@clerk/react-router

npm i @clerk/react-router@3.0.0-snapshot.v20260226185040 --save-exact

@clerk/shared

npm i @clerk/shared@4.0.0-snapshot.v20260226185040 --save-exact

@clerk/tanstack-react-start

npm i @clerk/tanstack-react-start@1.0.0-snapshot.v20260226185040 --save-exact

@clerk/testing

npm i @clerk/testing@2.0.0-snapshot.v20260226185040 --save-exact

@clerk/ui

npm i @clerk/ui@1.0.0-snapshot.v20260226185040 --save-exact

@clerk/upgrade

npm i @clerk/upgrade@2.0.0-snapshot.v20260226185040 --save-exact

@clerk/vue

npm i @clerk/vue@2.0.0-snapshot.v20260226185040 --save-exact

@royanger
Copy link
Member Author

!snapshot

@clerk-cookie
Copy link
Collaborator

Hey @royanger - the snapshot version command generated the following package versions:

Package Version
@clerk/agent-toolkit 0.3.0-snapshot.v20260226220202
@clerk/astro 3.0.0-snapshot.v20260226220202
@clerk/backend 3.0.0-snapshot.v20260226220202
@clerk/chrome-extension 3.0.0-snapshot.v20260226220202
@clerk/clerk-js 6.0.0-snapshot.v20260226220202
@clerk/dev-cli 1.0.0-snapshot.v20260226220202
@clerk/expo 3.0.0-snapshot.v20260226220202
@clerk/expo-passkeys 1.0.0-snapshot.v20260226220202
@clerk/express 2.0.0-snapshot.v20260226220202
@clerk/fastify 2.7.0-snapshot.v20260226220202
@clerk/localizations 4.0.0-snapshot.v20260226220202
@clerk/msw 0.0.1-snapshot.v20260226220202
@clerk/nextjs 7.0.0-snapshot.v20260226220202
@clerk/nuxt 2.0.0-snapshot.v20260226220202
@clerk/react 6.0.0-snapshot.v20260226220202
@clerk/react-router 3.0.0-snapshot.v20260226220202
@clerk/shared 4.0.0-snapshot.v20260226220202
@clerk/tanstack-react-start 1.0.0-snapshot.v20260226220202
@clerk/testing 2.0.0-snapshot.v20260226220202
@clerk/ui 1.0.0-snapshot.v20260226220202
@clerk/upgrade 2.0.0-snapshot.v20260226220202
@clerk/vue 2.0.0-snapshot.v20260226220202

Tip: Use the snippet copy button below to quickly install the required packages.
@clerk/agent-toolkit

npm i @clerk/agent-toolkit@0.3.0-snapshot.v20260226220202 --save-exact

@clerk/astro

npm i @clerk/astro@3.0.0-snapshot.v20260226220202 --save-exact

@clerk/backend

npm i @clerk/backend@3.0.0-snapshot.v20260226220202 --save-exact

@clerk/chrome-extension

npm i @clerk/chrome-extension@3.0.0-snapshot.v20260226220202 --save-exact

@clerk/clerk-js

npm i @clerk/clerk-js@6.0.0-snapshot.v20260226220202 --save-exact

@clerk/dev-cli

npm i @clerk/dev-cli@1.0.0-snapshot.v20260226220202 --save-exact

@clerk/expo

npm i @clerk/expo@3.0.0-snapshot.v20260226220202 --save-exact

@clerk/expo-passkeys

npm i @clerk/expo-passkeys@1.0.0-snapshot.v20260226220202 --save-exact

@clerk/express

npm i @clerk/express@2.0.0-snapshot.v20260226220202 --save-exact

@clerk/fastify

npm i @clerk/fastify@2.7.0-snapshot.v20260226220202 --save-exact

@clerk/localizations

npm i @clerk/localizations@4.0.0-snapshot.v20260226220202 --save-exact

@clerk/msw

npm i @clerk/msw@0.0.1-snapshot.v20260226220202 --save-exact

@clerk/nextjs

npm i @clerk/nextjs@7.0.0-snapshot.v20260226220202 --save-exact

@clerk/nuxt

npm i @clerk/nuxt@2.0.0-snapshot.v20260226220202 --save-exact

@clerk/react

npm i @clerk/react@6.0.0-snapshot.v20260226220202 --save-exact

@clerk/react-router

npm i @clerk/react-router@3.0.0-snapshot.v20260226220202 --save-exact

@clerk/shared

npm i @clerk/shared@4.0.0-snapshot.v20260226220202 --save-exact

@clerk/tanstack-react-start

npm i @clerk/tanstack-react-start@1.0.0-snapshot.v20260226220202 --save-exact

@clerk/testing

npm i @clerk/testing@2.0.0-snapshot.v20260226220202 --save-exact

@clerk/ui

npm i @clerk/ui@1.0.0-snapshot.v20260226220202 --save-exact

@clerk/upgrade

npm i @clerk/upgrade@2.0.0-snapshot.v20260226220202 --save-exact

@clerk/vue

npm i @clerk/vue@2.0.0-snapshot.v20260226220202 --save-exact

@royanger royanger marked this pull request as ready for review February 26, 2026 22:53
@royanger royanger requested a review from tmilewski February 26, 2026 22:53
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 26, 2026

📝 Walkthrough

Walkthrough

This pull request introduces a new client module for the @clerk/chrome-extension package with refactored createClerkClient functionality. A shared utility (clerk-client.ts) provides overloaded signatures to support both foreground (popup/side panel) and background service worker contexts. The old background-specific createClerkClient is deprecated. Package exports are added to enable subpath imports (`@clerk/chrome-extension/client`). A new browser extension JavaScript playground project is established with HTML, CSS, and TypeScript source files for testing the extension in Chrome. Build configurations and environment setup files are included alongside documentation.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(chrome-extension): Create js only create clerk client for extensions' describes the main feature of adding a JavaScript-only createClerkClient for Chrome Extensions, which aligns with the primary changes in the changeset.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.changeset/wild-pianos-matter.md:
- Around line 12-15: Fix the typos in the changeset: remove the stray trailing
single quote after the semicolon in the line declaring const clerk =
createClerkClient({ publishableKey }); and correct the misspelled function name
createClerkCleint to createClerkClient in the background worker example (the
line starting with const clerk = await createClerkClient(...)); keep the
existing await and background: true options intact.

In `@packages/chrome-extension/README.md`:
- Line 81: Typo in the README: replace the misspelled token `reasct-router` with
the correct `react-router` in the bullet that begins "SyncHost, Service Workers
and `react-router`" so the displayed link text and code-formatted token read
"react-router" consistently; update only the README.md bullet text containing
`reasct-router`.

In `@playground/browser-extension-js/src/popup.ts`:
- Around line 95-100: The createInfoRow function uses innerHTML with
interpolated label/value which can allow XSS if those strings are ever
untrusted; change createInfoRow to build the row with createElement and assign
textContent (or setAttribute for classes) to the label and value spans instead
of using innerHTML so the values are escaped and not interpreted as HTML.

ℹ️ Review info

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 64af60c and 99b151a.

⛔ Files ignored due to path filters (1)
  • packages/chrome-extension/src/__tests__/__snapshots__/client-exports.test.ts.snap is excluded by !**/*.snap
📒 Files selected for processing (25)
  • .changeset/wild-pianos-matter.md
  • .gitignore
  • packages/chrome-extension/README.md
  • packages/chrome-extension/client/package.json
  • packages/chrome-extension/package.json
  • packages/chrome-extension/src/__tests__/client-exports.test.ts
  • packages/chrome-extension/src/background/clerk.ts
  • packages/chrome-extension/src/client/index.ts
  • packages/chrome-extension/src/utils/__tests__/clerk-client.test.ts
  • packages/chrome-extension/src/utils/clerk-client.ts
  • packages/chrome-extension/tsup.config.ts
  • playground/browser-extension-js/.env
  • playground/browser-extension-js/.env.example
  • playground/browser-extension-js/.gitignore
  • playground/browser-extension-js/README.md
  • playground/browser-extension-js/build/manifest.json
  • playground/browser-extension-js/build/popup.css
  • playground/browser-extension-js/build/popup.html
  • playground/browser-extension-js/esbuild.config.mjs
  • playground/browser-extension-js/package.json
  • playground/browser-extension-js/pnpm-workspace.yaml
  • playground/browser-extension-js/src/popup.ts
  • playground/browser-extension-js/tsconfig.json
  • playground/browser-extension/README.md
  • playground/browser-extension/package.json

Comment on lines +12 to +15
const clerk = createClerkClient({ publishableKey });'

// Use createClerkCleint in a background service worker
const clerk = await createClerkClient({ publishableKey: 'pk_...', background: true });
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Typos in changeset will appear in published changelog.

  • Line 12: trailing quote after semicolon
  • Line 14: createClerkCleintcreateClerkClient
Proposed fix
-const clerk = createClerkClient({ publishableKey });'
+const clerk = createClerkClient({ publishableKey });

-// Use createClerkCleint in a background service worker
+// Use createClerkClient in a background service worker
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const clerk = createClerkClient({ publishableKey });'
// Use createClerkCleint in a background service worker
const clerk = await createClerkClient({ publishableKey: 'pk_...', background: true });
const clerk = createClerkClient({ publishableKey });
// Use createClerkClient in a background service worker
const clerk = await createClerkClient({ publishableKey: 'pk_...', background: true });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.changeset/wild-pianos-matter.md around lines 12 - 15, Fix the typos in the
changeset: remove the stray trailing single quote after the semicolon in the
line declaring const clerk = createClerkClient({ publishableKey }); and correct
the misspelled function name createClerkCleint to createClerkClient in the
background worker example (the line starting with const clerk = await
createClerkClient(...)); keep the existing await and background: true options
intact.

- [Standalone](https://github.com/clerk/clerk-chrome-extension-starter/tree/main): The extension is using its own authentication
- [WebSSO](https://github.com/clerk/clerk-chrome-extension-starter/tree/webapp_sso): The extensions shares authentication with a website in the same browser
- [Quickstart](https://github.com/clerk/clerk-chrome-extension-quickstart): The extension is using its own authentication
- [SyncHost, Service Workers and `react-router`](https://github.com/clerk/clerk-chrome-extension-demo): The extension shares auth with a website in the same browser, needs to access user information from Clerk in a service worker or needs to use `reasct-router`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Typo: "reasct-router" should be "react-router".

-- [SyncHost, Service Workers and `react-router`](https://github.com/clerk/clerk-chrome-extension-demo): The extension shares auth with a website in the same browser, needs to access user information from Clerk in a service worker or needs to use `reasct-router`
++ [SyncHost, Service Workers and `react-router`](https://github.com/clerk/clerk-chrome-extension-demo): The extension shares auth with a website in the same browser, needs to access user information from Clerk in a service worker or needs to use `react-router`
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- [SyncHost, Service Workers and `react-router`](https://github.com/clerk/clerk-chrome-extension-demo): The extension shares auth with a website in the same browser, needs to access user information from Clerk in a service worker or needs to use `reasct-router`
- [SyncHost, Service Workers and `react-router`](https://github.com/clerk/clerk-chrome-extension-demo): The extension shares auth with a website in the same browser, needs to access user information from Clerk in a service worker or needs to use `react-router`
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/chrome-extension/README.md` at line 81, Typo in the README: replace
the misspelled token `reasct-router` with the correct `react-router` in the
bullet that begins "SyncHost, Service Workers and `react-router`" so the
displayed link text and code-formatted token read "react-router" consistently;
update only the README.md bullet text containing `reasct-router`.

Comment on lines +95 to +100
function createInfoRow(label: string, value: string): HTMLDivElement {
const row = document.createElement('div');
row.className = 'user-info-row';
row.innerHTML = `<span class="info-label">${label}</span><span class="info-value">${value}</span>`;
return row;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Potential XSS via innerHTML with user data.

The createInfoRow function uses innerHTML with template literals containing user-supplied values (email, username). While the data originates from Clerk's backend, this pattern is unsafe if copied to production code. Consider using textContent or createElement for the spans:

Safer alternative using DOM APIs
 function createInfoRow(label: string, value: string): HTMLDivElement {
   const row = document.createElement('div');
   row.className = 'user-info-row';
-  row.innerHTML = `<span class="info-label">${label}</span><span class="info-value">${value}</span>`;
+  const labelSpan = document.createElement('span');
+  labelSpan.className = 'info-label';
+  labelSpan.textContent = label;
+  const valueSpan = document.createElement('span');
+  valueSpan.className = 'info-value';
+  valueSpan.textContent = value;
+  row.appendChild(labelSpan);
+  row.appendChild(valueSpan);
   return row;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function createInfoRow(label: string, value: string): HTMLDivElement {
const row = document.createElement('div');
row.className = 'user-info-row';
row.innerHTML = `<span class="info-label">${label}</span><span class="info-value">${value}</span>`;
return row;
}
function createInfoRow(label: string, value: string): HTMLDivElement {
const row = document.createElement('div');
row.className = 'user-info-row';
const labelSpan = document.createElement('span');
labelSpan.className = 'info-label';
labelSpan.textContent = label;
const valueSpan = document.createElement('span');
valueSpan.className = 'info-value';
valueSpan.textContent = value;
row.appendChild(labelSpan);
row.appendChild(valueSpan);
return row;
}
🧰 Tools
🪛 ast-grep (0.41.0)

[warning] 97-97: Direct modification of innerHTML or outerHTML properties detected. Modifying these properties with unsanitized user input can lead to XSS vulnerabilities. Use safe alternatives or sanitize content first.
Context: row.innerHTML = <span class="info-label">${label}</span><span class="info-value">${value}</span>
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://owasp.org/www-community/xss-filter-evasion-cheatsheet
- https://cwe.mitre.org/data/definitions/79.html

(dom-content-modification)


[warning] 97-97: Direct HTML content assignment detected. Modifying innerHTML, outerHTML, or using document.write with unsanitized content can lead to XSS vulnerabilities. Use secure alternatives like textContent or sanitize HTML with libraries like DOMPurify.
Context: row.innerHTML = <span class="info-label">${label}</span><span class="info-value">${value}</span>
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://www.dhairyashah.dev/posts/why-innerhtml-is-a-bad-idea-and-how-to-avoid-it/
- https://cwe.mitre.org/data/definitions/79.html

(unsafe-html-content-assignment)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@playground/browser-extension-js/src/popup.ts` around lines 95 - 100, The
createInfoRow function uses innerHTML with interpolated label/value which can
allow XSS if those strings are ever untrusted; change createInfoRow to build the
row with createElement and assign textContent (or setAttribute for classes) to
the label and value spans instead of using innerHTML so the values are escaped
and not interpreted as HTML.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants