Modèles d'extension Chrome
RÈGLES CRITIQUES
- OAuth (Google, GitHub, etc.) et SAML ne sont PAS pris en charge dans les popups ou panneaux latéraux -- utilisez
syncHostpour déléguer l'authentification à votre application web - Les liens par email (magic links) ne fonctionnent pas dans les popups -- le popup se ferme quand l'utilisateur clique en dehors, réinitialisant l'état de connexion
- Les panneaux latéraux ne rafraîchissent pas automatiquement l'état d'authentification -- les utilisateurs doivent fermer et rouvrir le panneau latéral après s'être connectés via l'application web
- Les service workers et content scripts n'ont PAS accès aux hooks React de Clerk -- utilisez
createClerkClient()ou le passage de messages - Les URL d'extension utilisent
chrome-extension://et nonhttp://-- toutes les URL de redirection doivent utiliserchrome.runtime.getURL('.') - Sans un CRX ID stable, chaque rebuild casse l'authentification -- configurez
keydans le manifest AVANT le déploiement - Les content scripts ne peuvent pas utiliser Clerk directement en raison des restrictions d'origine -- Clerk applique des origines autorisées strictes
- La protection contre les bots DOIT ÊTRE DÉSACTIVÉE dans le tableau de bord Clerk -- la détection de bots Cloudflare n'est pas prise en charge dans les environnements d'extension
Options d'authentification
| Méthode | Popup | Panneau latéral | syncHost (avec application web) |
|---|---|---|---|
| Email + OTP | Oui | Oui | Oui |
| Email + Lien | Non | Non | Oui |
| Email + Mot de passe | Oui | Oui | Oui |
| Nom d'utilisateur + Mot de passe | Oui | Oui | Oui |
| SMS + OTP | Oui | Oui | Oui |
| OAuth (Google, GitHub, etc.) | NON | NON | OUI |
| SAML | NON | NON | OUI |
| Passkeys | Oui | Oui | Oui |
| Google One Tap | Non | Non | Oui |
| Web3 | Non | Non | Oui |
Démarrage rapide (Plasmo)
npx create-plasmo --with-tailwindcss --with-src my-extension
cd my-extension
npm install @clerk/chrome-extension
Activez Native API dans le tableau de bord Clerk sous Applications natives. Obligatoire pour toutes les intégrations d'extension.
.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
Utilisez mode="modal" pour SignInButton -- naviguer vers une page séparée casse le flux du popup.
syncHost -- Synchroniser l'authentification avec l'application web
Utilisez ceci quand vous avez besoin d'OAuth, SAML, ou si vous voulez que l'extension reflète la connexion depuis votre application web.
Comment ça marche : L'extension lit le cookie de session Clerk du domaine de votre application web via host_permissions.
Étape 1 -- Variables d'environnement:
.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
Étape 2 -- Ajouter la prop 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 })}
>
Étape 3 -- Configurer host_permissions dans package.json:
{
"manifest": {
"key": "$CRX_PUBLIC_KEY",
"permissions": ["cookies", "storage"],
"host_permissions": [
"$PLASMO_PUBLIC_CLERK_SYNC_HOST/*",
"$CLERK_FRONTEND_API/*"
]
}
}
Étape 4 -- Ajouter l'ID de l'extension aux origines autorisées de l'application web via l'API Clerk:
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"]}'
Masquer les méthodes d'authentification non supportées dans le popup lors de l'utilisation de syncHost:
<SignIn
appearance={{
elements: {
socialButtonsRoot: 'plasmo-hidden',
dividerRow: 'plasmo-hidden',
},
}}
/>
Guide complet : references/sync-host.md
createClerkClient() pour Vanilla JS / Service Workers
Importez depuis @clerk/chrome-extension/client (pas @clerk/chrome-extension).
Service worker en arrière-plan (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
})
Le flag background: true garde les sessions fraîches même quand le popup/sidepanel est fermé. Sans lui, les tokens expirent après 60 secondes.
Popup avec 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()
})
Guide complet : references/create-clerk-client.md
Extension sans interface (pas de popup, pas de panneau latéral)
Pour les extensions qui s'exécutent entièrement en arrière-plan et se synchronisent avec une application web.
Utilise syncHost + createClerkClient avec background: true pour lire l'état d'authentification à partir des cookies de l'application web.
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
}
Nécessite host_permissions pour le domaine du sync host dans package.json.
Guide complet : references/headless-extension.md
Content Scripts
Les content scripts s'exécutent dans un monde JavaScript isolé injecté dans les pages web. Clerk ne peut pas être utilisé directement -- les restrictions d'origine l'empêchent.
Utilisez le passage de messages pour demander l'état d'authentification au service worker en arrière-plan :
// 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()
Guide complet : references/content-scripts.md
CRX ID stable
Sans une clé épinglée, Chrome dérive le CRX ID d'une clé aléatoire au moment de la build. Cela tourne à chaque rebuild, cassant les origines autorisées.
Option A -- Plasmo Itero (recommandé):
- Visitez Plasmo Itero Generate Keypairs
- Cliquez sur « Generate KeyPairs » -- sauvegardez la clé privée de manière sécurisée, copiez la clé publique et le CRX ID
Option B -- OpenSSL:
openssl genrsa -out key.pem 2048
# Utilisez Plasmo Itero pour convertir ou extraire la clé publique au format correct
.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/*"
]
}
}
Ajoutez chrome-extension://YOUR_STABLE_CRX_ID au tableau de bord Clerk > Origines autorisées.
Cache de tokens (persister entre les fermetures du popup)
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}>
| Type de stockage | Portée | Effacé lors de |
|---|---|---|
chrome.storage.local |
Appareil | Désinstallation ou effacement manuel |
chrome.storage.session |
Session | Fermeture du navigateur |
chrome.storage.sync |
Tous les appareils | Désinstallation (limité en taille, 8 KB) |
localStorage |
Popup uniquement | Fermeture du popup -- ne pas utiliser pour l'authentification |
Pièges courants
| Symptôme | Cause | Solution |
|---|---|---|
| Boucle de redirection à la connexion | CRX URL manquante dans les props ClerkProvider | Définissez afterSignOutUrl, signInFallbackRedirectUrl |
| Bouton OAuth non fonctionnel | OAuth non pris en charge dans le popup | Utilisez syncHost pour déléguer à l'application web |
| État d'authentification obsolète après connexion application web | syncHost non configuré |
Ajoutez la prop syncHost + host_permissions |
| Panneau latéral affiche déconnecté après connexion web | Limitation connue | L'utilisateur doit fermer et rouvrir le panneau latéral |
| L'arrière-plan ne peut pas obtenir de token après 60s | Session expirée, pas de rafraîchissement en arrière-plan | Utilisez createClerkClient({ background: true }) |
| Content script ne peut pas accéder à Clerk | Monde isolé + restrictions d'origine | Utilisez le passage de messages vers le service worker en arrière-plan |
| L'authentification se casse après rebuild | CRX ID en rotation | Configurez une clé stable via .env.chrome |
Variable PLASMO_PUBLIC_ non définie |
Mauvais fichier env | Utilisez .env.development, pas .env |
| Erreurs de protection contre les bots | Cloudflare non pris en charge dans les extensions | Désactivez la protection contre les bots dans le tableau de bord Clerk |
| Cache de tokens ne persiste pas | Utilisation de localStorage dans le popup |
Utilisez chrome.storage.local ou passez la prop tokenCache |
Exigences du plan
| Fonctionnalité | Plan |
|---|---|
| Authentification popup basique (email/mot de passe, OTP) | Gratuit |
| Passkeys | Gratuit |
| syncHost | Nécessite Pro (domaine personnalisé) |
| OAuth via syncHost | Pro + OAuth configuré sur l'application web |
| SAML via syncHost | Enterprise |
| Protection contre les bots | N/A -- doit être désactivée pour les extensions |
Voir aussi
clerk-setup- Installation initiale de Clerkclerk-custom-ui- Flux personnalisés et apparence