āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā ā š shadcn/directory/clerk/clerk-docs/getting-started/quickstart.chrome-extension ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā
<TutorialHero beforeYouStart={[ { title: "Set up a Clerk application", link: "/docs/getting-started/quickstart/setup-clerk", icon: "clerk", } ]} exampleRepo={[ { title: "Chrome Extension Quickstart Repo", link: "https://github.com/clerk/clerk-chrome-extension-quickstart" } ]} />
<Steps> ## Enable Native API <Include src="_partials/native-api-callout" />When creating your Clerk application in the Clerk Dashboard, your authentication options will depend on how you configure your Chrome Extension. Chrome Extensions can be used as a popup, a side panel, or in conjunction with a web app. Popups and side panels have limited authentication options. Learn more about what options are available.
This guide will use a popup.
Plasmo is a browser extension framework that includes hot reloading and creating development and production extension builds easily from the same code.
Plasmo strongly recommends using pnpm, so this guide will only use pnpm-based examples.
The following command creates an app with Tailwind CSS preconfigured and with a src/ directory. You can choose to remove one or both of those options.
pnpm create plasmo --with-tailwindcss --with-src clerk-chrome-extension
cd clerk-chrome-extension
@clerk/chrome-extensionThe Clerk Chrome Extension SDK gives you access to prebuilt components, React hooks, and helpers to make user authentication easier.
Add the SDK to your project:
pnpm add @clerk/chrome-extension
Plasmo offers several options for environment variable files, as the same codebase can be used for development and production builds, as well as for targeting different browsers. This guide uses .env.development and .env.chrome files.
The final result should resemble the following:
</SignedOut>
PLASMO_PUBLIC_CLERK_PUBLISHABLE_KEY={{pub_key}}
CLERK_FRONTEND_API=https://{{fapi_url}}
<ClerkProvider> to your appimport { ClerkProvider } from '@clerk/chrome-extension'
import { CountButton } from '~features/count-button'
import '~style.css'
const PUBLISHABLE_KEY = process.env.PLASMO_PUBLIC_CLERK_PUBLISHABLE_KEY
if (!PUBLISHABLE_KEY) {
throw new Error('Please add the PLASMO_PUBLIC_CLERK_PUBLISHABLE_KEY to the .env.development file')
}
function IndexPopup() {
return (
<ClerkProvider publishableKey={PUBLISHABLE_KEY}>
<div className="plasmo-flex plasmo-items-center plasmo-justify-center plasmo-h-16 plasmo-w-40">
<CountButton />
</div>
</ClerkProvider>
)
}
export default IndexPopup
You can control what content signed in and signed out users can see with Clerk's prebuilt components. Create a header with the following Clerk components. (With Chrome Extensions, you can also add this logic to a footer).
<SignedIn>: Children of this component can only be seen while signed in.<SignedOut>: Children of this component can only be seen while signed out.<UserButton />: A prebuilt component that comes styled out-of-the-box to show the avatar from the account the user is signed in with.<SignInButton />: An unstyled component that links to the sign-in page. For this example, because you have not specified any props or environment variables for the sign-in URL, the component will link to the Account Portal sign-in page.import {
ClerkProvider,
SignInButton,
SignedIn,
SignedOut,
UserButton,
} from '@clerk/chrome-extension'
import { CountButton } from '~features/count-button'
import '~style.css'
const PUBLISHABLE_KEY = process.env.PLASMO_PUBLIC_CLERK_PUBLISHABLE_KEY
if (!PUBLISHABLE_KEY) {
throw new Error('Please add the PLASMO_PUBLIC_CLERK_PUBLISHABLE_KEY to the .env.development file')
}
function IndexPopup() {
return (
<ClerkProvider publishableKey={PUBLISHABLE_KEY}>
<div className="plasmo-flex plasmo-items-center plasmo-justify-center plasmo-h-[600px] plasmo-w-[800px] plasmo-flex-col">
<header className="plasmo-w-full">
<SignedOut>
<SignInButton mode="modal" />
</SignedOut>
<SignedIn>
<UserButton />
</SignedIn>
</header>
<main className="plasmo-grow">
<CountButton />
</main>
</div>
</ClerkProvider>
)
}
export default IndexPopup
<ClerkProvider> props for Chrome Extension navigationTo avoid navigation errors, set the afterSignOutUrl, signInFallbackRedirectUrl and signUpFallbackRedirectUrl props for <ClerkProvider>. Chrome Extensions don't use an http URL, such as http://localhost:3000. Instead, they use a chrome-extension:// URL appended with an unique extension ID called a CRX ID. This URL is what you will pass to these props.
import {
ClerkProvider,
SignInButton,
SignedIn,
SignedOut,
UserButton,
} from '@clerk/chrome-extension'
import { CountButton } from '~features/count-button'
import '~style.css'
const PUBLISHABLE_KEY = process.env.PLASMO_PUBLIC_CLERK_PUBLISHABLE_KEY
const EXTENSION_URL = chrome.runtime.getURL('.')
if (!PUBLISHABLE_KEY) {
throw new Error('Please add the PLASMO_PUBLIC_CLERK_PUBLISHABLE_KEY to the .env.development file')
}
function IndexPopup() {
return (
<ClerkProvider
publishableKey={PUBLISHABLE_KEY}
afterSignOutUrl={`${EXTENSION_URL}/popup.html`}
signInFallbackRedirectUrl={`${EXTENSION_URL}/popup.html`}
signUpFallbackRedirectUrl={`${EXTENSION_URL}/popup.html`}
>
<div className="plasmo-flex plasmo-items-center plasmo-justify-center plasmo-h-[600px] plasmo-w-[800px] plasmo-flex-col">
<header className="plasmo-w-full">
<SignedOut>
<SignInButton mode="modal" />
</SignedOut>
<SignedIn>
<UserButton />
</SignedIn>
</header>
<main className="plasmo-grow">
<CountButton />
</main>
</div>
</ClerkProvider>
)
}
export default IndexPopup
Chrome Extensions have a unique CRX ID that rotates by default, which can cause errors with the Clerk integration. To avoid these problems, ensure that you have a consistent CRX ID in both development and production for your extension by following these steps:
.env.chrome file to store your public keyCreate an .env.chrome file and add your public key to it, as shown in the following example:
CRX_PUBLIC_KEY=<YOUR_PUBLIC_KEY>
package.json to use the new public keyPlasmo uses the package.json to generate a manifest.json on build, and allows for the use of environment variables in package.json.
In your package.json, in the manifest object:
key value to "$CRX_PUBLIC_KEY". This helps configure the consistent CRX ID for your extension.permissions array to include "cookies" and "storage". permissions specifies which permissions your extension requires.host_permissions array to include "http://localhost/*" and "$CLERK_FRONTEND_API/*". host_permissions specifies which hosts, or websites, have permission to sync auth state with your app.{
// The rest of your package.json file
"manifest": {
"key": "$CRX_PUBLIC_KEY",
"permissions": ["cookies", "storage"],
"host_permissions": ["http://localhost/*", "$CLERK_FRONTEND_API/*"]
}
}
pnpm dev to start your development server and create a buildPlasmo facilitates Chrome Extension development by automatically "hot loading" the app whenever you save a changed file in the project. This ensures the build/chrome-mv3-dev folder remains up to date. Without the plugin, you would need to manually execute the build command and reload your Chrome Extension after each change. Plasmo automates this process, streamlining development.
Run the following command to start your development environment. This also creates the build in build/chrome-mv3-dev, and rebuilds when you make changes to the extension.
pnpm dev
To load your Chrome Extension, follow these steps:
chrome://extensions.build/chrome-mv3-dev folder. Then select Select. Your extension will now be loaded and shown in the list of extensions.In your Chrome browser, open the extension popup. Ensure that the <SignInButton> appears, and that selecting it opens the <SignIn /> modal. Sign in and ensure that the <UserButton /> appears in the header.
[!WARNING] After signing up or signing in, your popup may appear to crash. Closing and reopening the popup should restart the extension and you should be signed in.
Your extension does not yet have anything to handle routing, and by default, the Clerk components attempt to redirect the user. See the guide on adding React Router to your Chrome Extension to add routing to your extension.
</Steps>
createClerkClient() function in a background service worker to ensure that the user's session is always fresh.
</Cards>
ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā