chrome-extension-auth
Skill2 starsChanged 51 days agoMITView on GitHub
Add user accounts to a Chrome MV3 extension with a backend. Covers Google SSO via chrome.identity.launchWebAuthFlow (OIDC id_token + server nonce, JWKS verification with jose) and manual email/password sign-in (argon2id hashing, email verification, password reset, account linking). Use for "login in chrome extension", "Google sign in extension", "launchWebAuthFlow", "chrome.identity", "OAuth chrome extension", "email password auth extension", "SSO", "session JWT extension", "sign in with Google MV3", "auth chrome-extension:// CORS", "extension ID redirect URI mismatch". Includes session storage (storage.local vs storage.session), 401/token-refresh handling, JWT secret rotation, and server-side revocation. Does NOT cover payments/entitlements, Chrome Web Store listing, or build/publish pipelines — see sibling skills.
In this repository4 other files it gives its agents.
The file
We split this skill into the rules it gives an agent
3 rules. About 0 are common, 1 is distinctive, and 2 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈1
Distinctive · estimate
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 9
Add sign-in and sessions to a Manifest V3 extension backed by a server.
- Very specific: line 56
Read references/troubleshooting.md before debugging a "sign-in opens and closes immediately" or "nonce mismatch" report — both have a …
- Very specific: line 61
Add schema: password_hash, password_algo on users.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Chrome Extension Auth
Add sign-in and sessions to a Manifest V3 extension backed by a server. Two proven paths, one shared session contract.
Scope
This skill covers: Google SSO (OAuth "Web application" client + launchWebAuthFlow), email/password
sign-in, session issuance and verification, extension-side storage and API calls, CORS, rate
limiting, and revocation.
This skill does not cover:
- Payments, subscriptions, entitlements →
chrome-extension-payments - Chrome Web Store listing content, screenshots, review policy →
chrome-web-store-listing - Extension scaffolding, build tooling, content scripts →
chrome-extension-dev - Packaging and publishing →
chrome-extension-deploy
Decision table
| Situation | Choose | Why |
| Want the fastest signup, no password support burden | Google SSO only | No password storage/reset flow to build or secure |
| Users without Google accounts, enterprise, or privacy-sensitive audience | Email/password (or passwordless OTP) | Not everyone has/wants a Google account |
| Want maximum reach, willing to build both | Both, with account linking | Same email can arrive via either path — link, don't duplicate |
| Want passwordless but no OAuth complexity | Email OTP (magic code) | Simpler than full password flow; still needs an email provider |
Both paths must converge on the same session contract: a server-issued session JWT, verified the same way, stored the same way in the extension. Do not build two different session formats.
Workflow A — Google SSO
- Register a Google OAuth Web application client (not "Chrome App" — see
references/google-sso-extension.md#oauth-client-setup). Add the redirect URIhttps://<extension-id>.chromiumapp.org/for both the dev extension ID (pinned via a manifestkey) and the Chrome Web Store ID (assigned after first publish, unknown until then). - In the extension manifest, add the
identitypermission and pin a dev key so the extension ID is stable across rebuilds — seereferences/google-sso-extension.md#manifest-and-dev-key. - Implement
beginGoogleSignIn: fetch a server-issued nonce, build the Google authorization URL withresponse_type=id_token, launchchrome.identity.launchWebAuthFlow, parse the ID token out of the redirect fragment. Full code inreferences/google-sso-extension.md#client-flow. - On the server, verify the ID token against Google's JWKS with
jose(aud,iss,exp,nonce,email_verified), burn the nonce, upsert the user, issue a session JWT. Full code inreferences/google-sso-backend.md. - Store the session in
chrome.storage.localfrom the background script only; attach it as aBearerheader on every API call made from the background script. Seereferences/google-sso-extension.md#session-and-api-calls. - Handle sign-out and 401s (session invalid/expired → clear and prompt re-login). See
references/sessions-cors-security.md#401-and-refresh.
Read references/troubleshooting.md before debugging a "sign-in opens and closes immediately" or
"nonce mismatch" report — both have a specific, known root cause.
Workflow B — Email/password
- Add schema:
password_hash,password_algoonusers;email_verificationsandpassword_reset_tokenstables. SQL inreferences/email-password.md#schema. - Signup: create an unverified user, send a 6-digit code (hashed, expiring, attempt-limited) via
an email provider behind an interface (Resend/SES/SMTP). Code in
references/email-password.md#signup-and-verification. - Password hashing: argon2id by default;
node:cryptoscryptfallback when a native module is not an option. Never roll your own KDF loop count. Code inreferences/email-password.md#password-hashing. - Login: constant-time password compare, generic error message ("invalid email or password") for
both "no such user" and "wrong password", per-IP and per-account throttling. Code in
references/email-password.md#login. - Password reset: request → emailed single-use token (hashed, expiring) → reset endpoint that
invalidates the token and bumps
token_version(see revocation below). Code inreferences/email-password.md#password-reset. - Account linking: if a Google sign-in's verified email matches an existing password account,
link
google_subonto that row instead of creating a duplicate — only whenemail_verifiedis true. Never auto-link an unverified email. Code inreferences/email-password.md#account-linking. - Issue the same session JWT shape as Workflow A step 4 so extension-side code (storage, API
client,
use-sessionhook) doesn't fork per auth method. - Build popup/options forms (signup, login, verify, forgot/reset password) that submit through
the background script, same as billing messages — never let a content script or a form
directly hold credentials outside the extension's own pages. UI notes in
references/email-password.md#ui-forms.
Alternative: skip passwords entirely with email OTP (passwordless) — same schema minus
password_hash, same session issuance. See references/email-password.md#passwordless-otp-simpler-alternative.
Security checklist
identitypermission present;optional_permissionsunaffected by auth- OAuth client is "Web application" type, both dev and store extension IDs registered as redirect URIs
- Nonce is server-issued, single-use, and expires (10 min is reasonable) — never trust a client-generated nonce for replay protection
- ID token verified against live JWKS (
aud,iss,exp,nonce,email_verified) — never decode without verifying - Session JWT is HS256 (or better) with a real expiry, signed with a secret ≥32 random bytes, never the placeholder default
- Session stored in
chrome.storage.local, read/written only by the background script, never exposed to content scripts or web pages - Every extension→server call carries
Authorization: Bearer <token>and runs from the background script only runtime.onMessagehandler validates the sender is the extension's own page before acting on any auth/account message (seereferences/sessions-cors-security.md#sender-validation)- Server CORS allowlist matches exact
chrome-extension://<id>origins — no wildcard, no prefix match - Rate limiting on nonce issuance, token exchange, login, signup, and password reset request
- Passwords hashed with argon2id or scrypt with real cost parameters — never plaintext, never unsalted, never fast hashes (MD5/SHA-1/SHA-256 alone)
- Password/email-verification/reset codes are hashed at rest, expiring, and attempt-limited
- Generic error messages on login (do not reveal whether the email exists)
- Account linking only on a verified email match
- A
token_version(or equivalent) column exists so sessions can be revoked server-side without waiting for natural expiry - Client secret (if any OAuth flow needs one) never ships in the extension bundle — only the public client ID does
Reference files
references/google-sso-extension.md— manifest, dev key,launchWebAuthFlowclient flow, session storage, background-only API calls, sender validationreferences/google-sso-backend.md— Hono routes,joseJWKS verification, nonce issuance, session JWT issuance/verification, user upsert, CORS, rate limitingreferences/email-password.md— full email/password design: schema, signup/verification, hashing, login, reset, account linking, UI forms, passwordless OTP alternativereferences/sessions-cors-security.md— storage.local vs storage.session, secret rotation, revocation, 401/refresh handling, sender validation detailreferences/troubleshooting.md— known failure modes and their fixes, including the extension-ID redirect-URI mismatch bug
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

