Pewterkit Guides
Clear, sourced fixes for launching an app: sign-in errors, and the launch checks worth doing before real customers arrive.
Sign-in guides
Fixes for the Firebase Auth and Google sign-in errors that stop launches: what the error means, why it happens, and the steps for your framework and host.
Sign-in screen & authDomain
- Firebase authDomain: what it is, where to find it, and when to change itauthDomain is the host that runs Firebase's sign-in helper at /__/auth/handler. Where to find it, what it controls, and when to change it.
- How to change Firebase authDomain to your own domainMove Firebase Auth's authDomain to your own domain: serve /__/auth/* on Firebase Hosting or via a reverse proxy, then update redirect URIs and domains.
- What is /__/auth/handler in Firebase Auth?/__/auth/handler is Firebase Auth's sign-in helper page. Why it must be an authorized redirect URI, what it serves, and how to fix its common errors.
- How to change the app name and logo on Google sign-in for a Firebase appGoogle's sign-in screens take your app name and logo from Google Auth Platform branding, shown only after brand verification. How to change them.
- Fix "The requested action is invalid" in Firebase Google loginFirebase's sign-in handler shows "The requested action is invalid" when it rejects a request. Check the API key, Authorized domains and the handler URL.
Authorized domains
- Firebase authorized domains: where the list lives and what to addWhere Firebase authorized domains live in the console, what's on the list by default, which hosts to add, and how to change it by API or Terraform.
- Wildcards in Firebase authorized domains: what works for subdomains and previewsFirebase documents no wildcard for authorized domains. Handle subdomains, preview URLs and customer domains, with a script to automate the list.
- Firebase authorized domains not working: domain is listed, sign-in still failsDomain already in Firebase authorized domains but sign-in still fails? Check the project, exact host, protocol, cached result and API key restrictions.
- Firebase auth/unauthorized-domain on localhost and 127.0.0.1New Firebase projects no longer authorize localhost by default. Add localhost or 127.0.0.1, use the Auth emulator, or test from a LAN IP.
- Firebase auth/unauthorized-domain on Vercel: fix preview deployments and productionEach Vercel deployment gets a new URL that Firebase hasn't authorized. Add stable hosts, use branch URLs or domains, and proxy /__/auth on production.
- Firebase Auth on Netlify: fix auth/unauthorized-domain on Deploy Previews and branch deploysNetlify Deploy Previews and permalinks use new hostnames Firebase hasn't authorized. Use branch deploys, add stable hosts, and proxy /__/auth.
redirect_uri_mismatch
- Error 400: redirect_uri_mismatch, what it means and how to fix itredirect_uri_mismatch means Google got a redirect URI that isn't on your OAuth client's list. Find the exact URI your app sent and register it.
- Error 400: redirect_uri_mismatch on localhost, fixed for local devOn localhost, Google matches scheme, host and port exactly. Pin your dev server's port and register the exact http://localhost callback URI.
Popup & redirect sign-in
- Firebase Google sign-in: should you use a popup or a redirect?signInWithPopup or signInWithRedirect for Firebase Google sign-in today? A decision table covering desktop, mobile, storage partitioning and COOP.
- Why Firebase says auth/popup-blocked, and how to get the sign-in popup to openauth/popup-blocked means the browser refused Firebase's sign-in window. Call signInWithPopup first in the click, move awaits out, or redirect.
- Firebase auth/popup-closed-by-user, when it's really the user and when it isn'tauth/popup-closed-by-user means Firebase saw the sign-in window as closed. Often the user closed it, but a COOP header or an error page can cause it too.
- Firebase auth/cancelled-popup-request, why a second popup cancels the firstauth/cancelled-popup-request means a second popup sign-in started before the first ended. Block double clicks and keep sign-in out of effects.
- Firebase signInWithRedirect not working? Fix it by causeFirebase signInWithRedirect returns you signed out or getRedirectResult gives null? Fix storage partitioning, consumed results and listener timing.
- Firebase signInWithRedirect on localhost: three setups that workFirebase signInWithRedirect fails on localhost? Authorize localhost, then use a dev proxy over HTTPS, a popup in dev, or the Auth Emulator.
- signInWithRedirect in React (Vite): a minimal example that worksMinimal React + Vite example of Firebase signInWithRedirect, getRedirectResult and onAuthStateChanged that survives StrictMode and router guards.
- Fix "missing initial state" in Flutter Firebase Google sign-inFix "Unable to process request due to missing initial state" in Flutter web and Android apps using firebase_auth and google_sign_in, with Dart code.
- Firebase sign-in fails in Firefox and Safari: "missing initial state" and blocked popupsWhy Firebase redirect sign-in fails with "missing initial state" in Firefox and Safari, why Safari blocks the popup, and Firebase's five fixes.
By framework
- Firebase Google sign-in with Next.js (App Router, Vercel)Add Firebase Google sign-in to a Next.js App Router app: 'use client' setup, NEXT_PUBLIC_ env vars, authorized domains and a /__/auth rewrite on Vercel.
- Firebase Google sign-in with Vite and ReactSet up Firebase Google login in a Vite React app: VITE_ env vars, an auth context, authorized domains, and a /__/auth proxy on Netlify or Vercel.
- Firebase Google sign-in with Vue 3 and NuxtFirebase Google sign-in for Vue 3 and Nuxt: VueFire composables, a client-only Nuxt plugin, authorized domains and a Nitro routeRules proxy for /__/auth.
- Firebase Google sign-in with SvelteKitFirebase Google sign-in for SvelteKit 3 and 2: browser-only init, public env vars, authorized domains, and a handle hook that proxies /__/auth to Firebase.
- Firebase Google sign-in in Angular 20+ with AngularFireAdd Firebase Google sign-in to a standalone Angular 20+ app with AngularFire: matching versions, popup code, SSR caveats and /__/auth proxy setup.
- Set up Firebase Google sign-in in a Flutter web appSet up Google sign-in in a Flutter web app with firebase_auth: popup vs redirect, google_sign_in 7.x web changes, authorized domains and your own domain.
By host & builder
- Firebase Google sign-in on Cloudflare PagesGet Firebase Google sign-in working on Cloudflare Pages: authorize pages.dev and custom domains, and proxy /__/auth/ with a Pages Function.
- Connect a custom domain to Firebase Hosting and use it for sign-inConnect a custom domain to Firebase Hosting (TXT check, A records, SSL), then use it as authDomain so Google sign-in shows your own domain.
- Firebase Google sign-in for apps on Cloud RunSet up Firebase Google sign-in for a Cloud Run app: authorize run.app or your domain, choose a domain option, show your domain, check ID tokens.
- FlutterFlow Google sign-in with Firebase: setup, domains and the firebaseapp.com screenSet up Google sign-in in FlutterFlow with Firebase Auth, authorize test, run and custom domains, and see what changing authDomain involves.
- Firebase Auth on Replit: domains, Secrets and custom domainsFirebase Google sign-in on Replit: which replit.dev and replit.app hosts to authorize, where config goes, and what a custom domain means for authDomain.
- Fixing Firebase Google sign-in in Lovable, Bolt and Cursor appsFix Firebase Google sign-in in Lovable, Bolt.new or Cursor apps: missing preview domains, wrong config, popups in previews, plus a fix-it prompt.
- Add Firebase Google sign-in to a Webflow siteAdd Firebase Google sign-in to Webflow with a module script in custom code, authorize webflow.io and your domain, and learn why authDomain stays put.
Google OAuth errors & consent screen
- "Access blocked: This app's request is invalid" - find the real error and fix itGoogle's "Access blocked" screen hides the real error. Open the error details, read the code (redirect_uri_mismatch, invalid_request) and fix that cause.
- "Error 400: invalid_request" on Google sign-in: read the details and fix the causeError 400: invalid_request means Google rejected the OAuth request. Read the detail line, then fix missing params, OOB, custom schemes, HTTP or PKCE.
- "Access blocked: app has not completed the Google verification process" - why and how to fix it"Access blocked: app has not completed the Google verification process" (403 access_denied) means Testing mode. Add test users, publish, or verify.
- Google OAuth consent screen: setup, Internal vs External, and why it isn't showingWhere the Google OAuth consent screen lives now (Google Auth Platform), Internal vs External, setup steps, and why the consent screen doesn't show.
- Sign in with Google button or One Tap not showing: how to fix itFix a Google Identity Services button or One Tap that won't render: JavaScript origins, script loading, CSP, FedCM, cooldowns and origin_mismatch.
Supabase
- Supabase Google OAuth setup (and what to check when it isn't working)Set up Google sign-in with Supabase Auth: Google Cloud client, Supabase callback URI, provider settings, signInWithOAuth code and a fix checklist.
- Supabase Google OAuth redirects to localhost after login: how to fix itGoogle login works but production users land on localhost:3000? Fix the Supabase Site URL, add redirectTo, and allow-list the exact URL. Step-by-step.
- Supabase Redirect URLs explained: allow list, wildcards and local configHow the Supabase Redirect URLs allow list works: wildcard syntax, Vercel and Netlify preview patterns, additional_redirect_urls and fixes.
- Google sign-in shows your supabase.co URL: fix it with a Supabase custom domainWhy Google's sign-in screen names your supabase.co project URL, and how a Supabase custom domain and Google branding show your own domain and name.
Auth.js, Better Auth & Auth0
- Fix NextAuth (Auth.js) Google redirect_uri_mismatchFix Error 400 redirect_uri_mismatch in Auth.js / NextAuth: the exact /api/auth/callback/google URIs to add, AUTH_URL, trustHost and Vercel previews.
- Better Auth Google callback URL and redirect URI setupThe redirect URI Better Auth's Google provider uses (/api/auth/callback/google), plus baseURL, BETTER_AUTH_URL, trustedOrigins and mismatch fixes.
- Auth0 custom domain: setup, Google sign-in and troubleshootingSet up an Auth0 custom domain so Google stops showing tenant.auth0.com: certificates, CNAME, Cloudflare, Google keys and Pending Verification fixes.
Reference
Launch checks
What to look at before real customers arrive: keys in your public code, browser protections, payments, email and your domain. Each guide explains the problem and the fix, with sources.
Exposed keys & source code
- Stripe secret key exposed in your frontend code: rotate it, then move it to the serverAn sk_live_ or rk_live_ key in your JavaScript bundle can be used by anyone. Rotate it in the Stripe Dashboard, then move it to a server function.
- OpenAI API key in your React or Vite frontend: rotate it and move calls to a backendAn OpenAI key in browser JavaScript lets anyone run requests on your account. Rotate it, then call the API from a server route that holds the key.
- Supabase service_role key in your frontend bundle: replace it and switch the old key offThe service_role key bypasses every Row Level Security policy. If it is in your browser bundle, replace it with a secret key and deactivate the legacy keys.
- Source maps in production: what they show and how to stop publishing themA public .map file lets anyone read your app's original code, comments and file names. How to switch source maps off in Vite, Next.js and React builds.
Security headers
- HSTS missing: how to add the Strict-Transport-Security header to your appStrict-Transport-Security tells browsers to always use HTTPS for your site. Which value to use and how to add it on Netlify, Vercel and Cloudflare.
- Missing X-Frame-Options: add clickjacking protection with frame-ancestorsClickjacking protection stops other sites from loading your app in a hidden frame. Set CSP frame-ancestors (and X-Frame-Options for older browsers) as headers.
- Missing X-Content-Type-Options header: add nosniff the right wayX-Content-Type-Options nosniff tells browsers to trust your Content-Type instead of guessing. What it does, what can break, and how to add it.
- Missing Referrer-Policy: choose a value and add the headerReferrer-Policy controls how much of your page address is sent to other sites. Pick strict-origin-when-cross-origin or stricter, and set it as a header.
Payments
- Stripe test mode on a live site: switch from pk_test to your live keysA pk_test_ key on your live site means checkout runs in a Stripe sandbox and nobody can pay you. How to switch to live keys without breaking checkout.
- Stripe checkout success_url still set to localhost or a preview addressAfter paying, customers land on localhost or a preview address instead of your site. Build success_url and cancel_url from your live domain.
Email deliverability
- No SPF record found: add one SPF record for your domainWithout an SPF record, mail from your domain (sign-in links, receipts) is more likely to land in spam. How to add one TXT record and avoid the common mistakes.
- No DMARC record found: add one at _dmarc, start with p=noneA DMARC record tells receivers what to do with mail that fakes your domain. Add a TXT record at _dmarc with p=none, read the reports, then tighten.
- Emails from a new domain going to spam: authenticate first, then build up slowlyNew domains have no sending history, so missing SPF, DKIM or DMARC hits hard. Set up all three, then start with low volume and grow slowly.
Domain, DNS & HTTPS
- Check your domain's expiry date, and make sure it renewsWhen a domain expires, your website and email stop working. How to look up the expiry date, switch on auto-renew and keep renewal notices reaching you.
- Check when your SSL certificate expires, and whether renewal is workingAn expired HTTPS certificate puts a full-page warning in front of your site. How to read the expiry date, and how to tell if automatic renewal has stalled.
- HTTP not redirecting to HTTPS: send every visitor to the HTTPS addressIf http:// still loads your site, visitors land on the unencrypted version and browsers warn about it. Turn on the HTTPS redirect on your host.
- www not working, but the domain without www does (or the other way around)If www.yourapp.com (or the bare domain) shows an error, visitors who type it never reach you. Add the missing DNS record and redirect one to the other.
- DNSSEC basics: what it does and how to switch it on safelyDNSSEC signs your DNS records so resolvers can reject forged answers. What it protects, how to switch it on, and the one mistake that takes a domain offline.
Privacy & consumer rules
- Privacy policy for an app in the US: the link, the effective date and the Do Not Track lineWhat a US privacy policy for a web app needs under California's CalOPPA: a visible link, an effective date and a Do Not Track statement. With a template.
- The "Do Not Sell or Share My Personal Information" link, and the "Your Privacy Choices" alternativeWhen a US app needs a "Do Not Sell or Share My Personal Information" or "Your Privacy Choices" link, where it goes, and what it should do.
- Global Privacy Control (GPC): what the signal is and how your app can honor itWhat the Global Privacy Control signal is, how to detect Sec-GPC and navigator.globalPrivacyControl, and how a web app can honor it as an opt-out.
- Subscription auto-renewal terms and online cancellation: what ROSCA and California's law ask of your checkoutHow a US subscription app shows auto-renewal terms by the subscribe button and offers online cancellation, per ROSCA and California's renewal law.
- Cookie consent for UK and EU visitors: hold trackers back until people say yesFor UK and EU visitors, ad and most analytics trackers wait for a yes on your cookie banner. How to hold them back, and the UK analytics exception.
- UK website legal requirements: the business details your footer should showThe business details a UK site that sells online shows: name, geographic address, email, company number and registered office. With a footer template.
Accessibility
- "Images must have alternate text": how to fix missing alt text in your appFix "Images must have alternate text": what the axe rule and WCAG 1.1.1 ask, when to write alt text, when to use alt="", and a prompt for your app builder.
- "Form elements must have labels": how to label every input in your sign-up and checkout formsFix "Form elements must have labels" and "input missing associated label": label for/id, wrapping labels, aria-label, and why placeholder isn't a label.
- "Buttons must have discernible text": how to name icon-only buttons and linksFix "Buttons must have discernible text" and "Links must have discernible text": give icon-only buttons and image links an accessible name.
- The viewport meta tag: one line that fixes tiny mobile pages, without blocking zoomThe viewport meta tag to use, why a missing one makes phones show your site zoomed out, and why user-scalable=no and maximum-scale=1 block zoom.
Search & sharing
- Your page title still says "Lovable App" or "Vite + React": how to change itYour browser tab and Google still show "Lovable App", "Vite + React" or "React App". Where the title lives in index.html, what to write, and per-page titles.
- Replace the default Vite or Lovable favicon with your own iconYour tab still shows the Vite logo or your builder's icon. Replace public/vite.svg, update the link rel="icon" line, and meet Google's favicon rules.
- Meta description missing, or still "Lovable Generated Project": how to add a real oneAdd a real meta description to a Vite, Lovable or React app, replace "Lovable Generated Project", and write one Google may use as your snippet.
- Open Graph image not showing: fix the link preview for your appWhy your link preview shows no image, the builder's screenshot or template text, and the og:image tags that give shared links your own picture.
- "Excluded by noindex tag": find and remove the noindex your app launched withSearch Console says "Excluded by noindex tag" or your site won't appear on Google. Find the meta robots, X-Robots-Tag or robots.txt rule and remove it.
- Add a sitemap.xml to your Vite, Lovable or React appYour app has no sitemap.xml. Write one for a single-page app, put it in public/, list it in robots.txt and submit it in Search Console.
- Your canonical tag points to lovable.app or vercel.app: point it at your own domainYour canonical link still names a lovable.app, vercel.app or netlify.app address, so Google credits the builder's host. Point it at your own domain.
Launch-day basics
- 404 on refresh: fix deep links in a single-page app on Vercel, Netlify and CloudflareYour app works from the homepage but /pricing returns 404 when refreshed or opened from a link. The SPA rewrite for Vercel, Netlify and Cloudflare.
- "Mixed content: the page was loaded over HTTPS, but requested an insecure resource": how to fix itFix "was loaded over HTTPS, but requested an insecure script / image / stylesheet": find the http:// address, switch it to https, or upgrade requests.