← Files ClerkARCHIVED FILE

skills/clerk-chrome-extension-patterns/references/create-clerk-client.md

3.9 KB · Oct 4, 2026 · 12:23 UTC

↓ Download file

# createClerkClient() -- Vanilla JS and Service Workers

## When to Use

Use `createClerkClient()` when:
- Your extension doesn't use React
- You need Clerk in a background service worker
- You need Clerk in a content script context (via message passing from background)
- You want to keep sessions fresh without a visible popup

Import from `@clerk/chrome-extension/client`, NOT from `@clerk/chrome-extension`.

## Background Service Worker

The key option is `background: true`. This tells Clerk to refresh the session token continuously, even when no popup or side panel is open. Without it, tokens expire after 60 seconds of the UI being closed.

`src/background/index.ts`:
```typescript
import { createClerkClient } from '@clerk/chrome-extension/client'

const publishableKey = process.env.PLASMO_PUBLIC_CLERK_PUBLISHABLE_KEY

if (!publishableKey) {
  throw new Error('Missing PLASMO_PUBLIC_CLERK_PUBLISHABLE_KEY')
}

async function getToken(): Promise<string | null> {
  const clerk = await createClerkClient({
    publishableKey,
    background: true,
  })

  if (!clerk.session) return null

  return await clerk.session.getToken()
}

chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
  getToken()
    .then((token) => sendResponse({ token }))
    .catch((error) => {
      console.error('[Background service worker] Error:', JSON.stringify(error))
      sendResponse({ token: null })
    })
  return true
})
```

The listener MUST `return true` to keep the message channel open for the async `sendResponse` call.

## Requesting the Token from a Tab or Content Script

```typescript
// tabs/my-tab.tsx or a content script
async function getTokenFromBackground(): Promise<string | null> {
  return new Promise((resolve) => {
    chrome.runtime.sendMessage({ type: 'GET_TOKEN' }, (response) => {
      resolve(response?.token ?? null)
    })
  })
}

async function makeAuthenticatedRequest() {
  const token = await getTokenFromBackground()
  if (!token) {
    console.warn('User not signed in')
    return
  }

  const res = await fetch('https://api.example.com/me', {
    headers: { Authorization: `Bearer ${token}` },
  })

  return res.json()
}
```

## Vanilla JS Popup (no React)

For popups or side panels that use plain TypeScript instead of React:

`src/popup.ts`:
```typescript
import { createClerkClient } from '@clerk/chrome-extension/client'

const publishableKey = process.env.CLERK_PUBLISHABLE_KEY
const EXTENSION_URL = chrome.runtime.getURL('.')
const POPUP_URL = `${EXTENSION_URL}popup.html`

const clerk = createClerkClient({ publishableKey })
const contentEl = document.getElementById('content') as HTMLDivElement

function render() {
  const email = clerk.user?.primaryEmailAddress?.emailAddress
  contentEl.textContent = email ?? 'Not signed in'
}

clerk.load({
  afterSignOutUrl: POPUP_URL,
  signInForceRedirectUrl: POPUP_URL,
  signUpForceRedirectUrl: POPUP_URL,
  allowedRedirectProtocols: ['chrome-extension:'],
}).then(() => {
  clerk.addListener(render)
  render()
})
```

`allowedRedirectProtocols: ['chrome-extension:']` is required to allow redirects to `chrome-extension://` URLs.

## createClerkClient() Options

| Option | Type | Description |
|--------|------|-------------|
| `publishableKey` | `string` | Required. Your Clerk publishable key. |
| `background` | `boolean` | Set `true` in service workers to keep sessions fresh. |
| `syncHost` | `string` | The web app domain to sync auth from (headless extensions). |

## Making Authenticated API Calls from Background

```typescript
async function callMyAPI() {
  const clerk = await createClerkClient({ publishableKey, background: true })

  if (!clerk.session) return

  const token = await clerk.session.getToken()

  const res = await fetch('https://api.yourapp.com/data', {
    headers: { Authorization: `Bearer ${token}` },
  })

  return res.json()
}
```

## Docs

[createClerkClient() reference](https://clerk.com/docs/reference/chrome-extension/create-clerk-client)

SHA-256: 3c5aee8f5ef0d3c0df9d96a2717b561b16ba3660f5e97a35aa753fd71a8088ea