mcpField
C
clerk-chrome-extension-patterns

clerk-chrome-extension-patterns

github.com/midudev開発7.0k58 回インストール1 週間前に更新
リポジトリ

clerk-chrome-extension-patterns について

Clerk を使って Chrome 拡張機能を開発する人向けの認証パターン集です。ポップアップやサイドパネルの制約、Web アプリとのセッション同期、バックグラウンド処理、障害対応を扱います。

主な機能

  1. 01ポップアップとサイドパネルの認証制約
  2. 02syncHost による Web アプリとの同期
  3. 03createClerkClient() によるバックグラウンド認証
  4. 04メッセージング経由のコンテンツスクリプト認証
  5. 05安定した CRX ID とトークンキャッシュの設定

活用シーン

  1. 01Chrome 拡張機能への Clerk サインイン導入
  2. 02OAuth または SAML 認証の Web アプリへの委譲
  3. 03Service Worker からのセッショントークン取得
  4. 04拡張機能の再ビルド後に起きる認証障害の調査

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/midudev/autoskills --skill clerk-chrome-extension-patterns

インストール後、Claude Code で/clerk-chrome-extension-patternsを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

evals/
evals.json
references/
content-scripts.md
create-clerk-client.md
headless-extension.md
sync-host.md
templates/chrome-ext-basic-auth/
package.json
tsconfig.json
templates/chrome-ext-basic-auth/src/
popup.tsx

詳細

Chrome 拡張機能のパターン

重要なルール

  1. OAuth(Google、GitHub など)と SAML は、ポップアップやサイドパネルではサポートされていません。syncHost を使用して、認証をウェブアプリに委任してください。
  2. メールリンク(マジックリンク)はポップアップでは機能しません。ユーザーが外側をクリックするとポップアップが閉じ、サインイン状態がリセットされます。
  3. サイドパネルでは認証状態が自動更新されません。ウェブアプリ経由でサインインした後、ユーザーはサイドパネルを閉じて再度開く必要があります。
  4. サービスワーカーとコンテンツスクリプトから Clerk の React フックにアクセスすることはできません。createClerkClient() またはメッセージパッシングを使用してください。
  5. 拡張機能の URL では http:// ではなく chrome-extension:// を使用します。すべてのリダイレクト URL で chrome.runtime.getURL('.') を使用してください。
  6. 安定した CRX ID がないと、ビルドのたびに認証が機能しなくなります。デプロイ前に、マニフェストで key を設定してください。
  7. コンテンツスクリプトはオリジンの制約により Clerk を直接使用できません。Clerk では許可するオリジンが厳格に制限されています。
  8. Clerk ダッシュボードでボット対策を無効にする必要があります。Cloudflare のボット検出は拡張機能の環境ではサポートされていません。

認証オプション

方法ポップアップサイドパネルsyncHost(ウェブアプリと連携)
メール + OTPはいはいはい
メール + リンクいいえいいえはい
メール + パスワードはいはいはい
ユーザー名 + パスワードはいはいはい
SMS + OTPはいはいはい
OAuth(Google、GitHub など)いいえいいえはい
SAMLいいえいいえはい
パスキーはいはいはい
Google One Tapいいえいいえはい
Web3いいえいいえはい

クイックスタート(Plasmo)

npx create-plasmo --with-tailwindcss --with-src my-extension
cd my-extension
npm install @clerk/chrome-extension

Clerk ダッシュボードの「Native applications」で Native API を有効にします。すべての拡張機能との連携で必要です。

.env.development:

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

src/popup.tsx:

import { ClerkProvider, Show, SignInButton, SignUpButton, UserButton } from '@clerk/chrome-extension'

const PUBLISHABLE_KEY = process.env.PLASMO_PUBLIC_CLERK_PUBLISHABLE_KEY
const EXTENSION_URL = chrome.runtime.getURL('.')

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

function IndexPopup() {
  return (
    <ClerkProvider
      publishableKey={PUBLISHABLE_KEY}
      afterSignOutUrl={`${EXTENSION_URL}/popup.html`}
      signInFallbackRedirectUrl={`${EXTENSION_URL}/popup.html`}
      signUpFallbackRedirectUrl={`${EXTENSION_URL}/popup.html`}
    >
      <Show when="signed-out">
        <SignInButton mode="modal" />
        <SignUpButton mode="modal" />
      </Show>
      <Show when="signed-in">
        <UserButton />
      </Show>
    </ClerkProvider>
  )
}

export default IndexPopup

SignInButton には mode="modal" を使用してください。別ページに移動すると、ポップアップのフローが機能しなくなります。

syncHost — ウェブアプリとの認証状態の同期

OAuth や SAML が必要な場合、またはウェブアプリでのサインインを拡張機能に反映させる場合に使用します。

仕組み:拡張機能は host_permissions を介して、ウェブアプリのドメインから Clerk のセッションクッキーを読み取ります。

ステップ 1 — 環境変数:

.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

ステップ 2 — syncHost プロパティを追加:

const SYNC_HOST = process.env.PLASMO_PUBLIC_CLERK_SYNC_HOST

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

ステップ 3 — package.json で host_permissions を設定:

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

ステップ 4 — Clerk API を使って、ウェブアプリの許可済みオリジンに拡張機能の ID を追加:

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"]}'

syncHost の使用時に、ポップアップでサポートされていない認証方法を非表示にする:

<SignIn
  appearance={{
    elements: {
      socialButtonsRoot: 'plasmo-hidden',
      dividerRow: 'plasmo-hidden',
    },
  }}
/>

完全なガイド:references/sync-host.md

Vanilla JS/サービスワーカーでの createClerkClient()

@clerk/chrome-extension ではなく、@clerk/chrome-extension/client からインポートします。

バックグラウンドサービスワーカー(src/background/index.ts):

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

const publishableKey = process.env.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] Error:', JSON.stringify(error))
      sendResponse({ token: null })
    })
  return true
})

background: true フラグを設定すると、ポップアップやサイドパネルが閉じている間もセッションが最新の状態に保たれます。設定しない場合、トークンは 60 秒後に期限切れになります。

Vanilla JS を使ったポップアップ(src/popup.ts):

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

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

const clerk = createClerkClient({ publishableKey })

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

完全なガイド:references/create-clerk-client.md

ヘッドレス拡張機能(ポップアップもサイドパネルもなし)

完全にバックグラウンドで動作し、ウェブアプリと同期する拡張機能向けです。

syncHost と background: true を指定した createClerkClient を使用し、ウェブアプリのクッキーから認証状態を読み取ります。

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

const publishableKey = process.env.PLASMO_PUBLIC_CLERK_PUBLISHABLE_KEY
const syncHost = process.env.PLASMO_PUBLIC_CLERK_SYNC_HOST

async function getAuthenticatedUser() {
  const clerk = await createClerkClient({
    publishableKey,
    syncHost,
    background: true,
  })
  return clerk.user
}

package.json で、同期ホストのドメインに対する host_permissions が必要です。

完全なガイド:references/headless-extension.md

コンテンツスクリプト

コンテンツスクリプトは、ウェブページに挿入された隔離された JavaScript 環境で実行されます。オリジンの制約により、Clerk を直接使用できません。

メッセージパッシングを使用して、バックグラウンドサービスワーカーに認証状態を問い合わせてください。

// content.ts
async function getToken(): Promise<string | null> {
  return new Promise((resolve) => {
    chrome.runtime.sendMessage({ type: 'GET_TOKEN' }, (response) => {
      resolve(response?.token ?? null)
    })
  })
}

async function main() {
  const token = await getToken()
  if (!token) return
  // use token for authenticated API calls
}

main()

完全なガイド:references/content-scripts.md

安定した CRX ID

固定されたキーがない場合、Chrome はビルド時にランダムなキーから CRX ID を生成します。再ビルドするたびに変わるため、許可されたオリジンが無効になります。

オプション A -- Plasmo Itero(推奨):

  1. Plasmo Itero キーペアの生成にアクセスします
  2. 「Generate KeyPairs」をクリックし、秘密鍵を安全に保存して、公開鍵と CRX ID をコピーします

オプション B -- OpenSSL:

openssl genrsa -out key.pem 2048
# Use Plasmo Itero to convert or extract the public key in correct format

.env.chrome:

CRX_PUBLIC_KEY="<PUBLIC KEY from Itero>"

package.json:

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

Clerk Dashboard > Allowed Origins に chrome-extension://YOUR_STABLE_CRX_ID を追加します。

トークンキャッシュ(ポップアップを閉じても保持)

const tokenCache = {
  async getToken(key: string) {
    const result = await chrome.storage.local.get(key)
    return result[key] ?? null
  },
  async saveToken(key: string, token: string) {
    await chrome.storage.local.set({ [key]: token })
  },
  async clearToken(key: string) {
    await chrome.storage.local.remove(key)
  },
}

<ClerkProvider publishableKey={PUBLISHABLE_KEY} tokenCache={tokenCache}>
ストレージの種類スコープ消去されるタイミング
chrome.storage.localデバイスアンインストール時または手動で消去したとき
chrome.storage.sessionセッションブラウザーを閉じたとき
chrome.storage.syncすべてのデバイスアンインストール時(サイズ制限あり、8KB)
localStorageポップアップのみポップアップを閉じたとき。認証には使用しないでください

よくある落とし穴

症状原因対処方法
サインイン時にリダイレクトがループするClerkProvider の props に CRX URL がないafterSignOutUrl と signInFallbackRedirectUrl を設定します
OAuth ボタンが機能しないポップアップでは OAuth がサポートされていないsyncHost を使用してウェブアプリに処理を委任します
ウェブアプリへのサインイン後も認証状態が古いままsyncHost が設定されていないsyncHost prop と host_permissions を追加します
ウェブでのサインイン後、サイドパネルにサインアウト状態が表示される既知の制限事項ユーザーがサイドパネルを閉じて再度開く必要があります
60 秒経過後、バックグラウンドでトークンを取得できないセッションの有効期限が切れ、バックグラウンドでの更新がないcreateClerkClient({ background: true }) を使用します
コンテンツスクリプトから Clerk にアクセスできない分離されたワールドとオリジンの制限メッセージパッシングを使用してバックグラウンドサービスワーカーに渡します
再ビルド後に認証が機能しなくなるCRX ID が変わった.env.chrome で安定したキーを設定します
PLASMO_PUBLIC_ 変数が未定義環境変数ファイルが間違っている.env ではなく .env.development を使用します
ボット保護のエラーが発生するCloudflare は拡張機能でサポートされていないClerk Dashboard でボット保護を無効にします
トークンキャッシュが保持されないポップアップで localStorage を使用しているchrome.storage.local を使用するか、tokenCache prop を渡します

プラン要件

機能プラン
基本的なポップアップ認証(メールアドレス/パスワード、OTP)Free
パスキーFree
syncHostPro が必要(カスタムドメイン)
syncHost 経由の OAuthPro + ウェブアプリでの OAuth 設定
syncHost 経由の SAMLEnterprise
ボット保護該当なし。拡張機能では無効にする必要があります

関連項目

  • clerk-setup - Clerk の初期インストール
  • clerk-custom-ui - カスタムフローと外観

コメント