Sign in with Google button or One Tap not showing: how to fix it
When the Google Identity Services (GIS) button stays blank or fails on click, the cause is usually an origin missing from Authorized JavaScript origins (exact scheme, host and port), or the gsi/client script being blocked or used before it loads.
When only One Tap is missing, it is usually suppressed on purpose: the page isn't on HTTPS, a recent close started a cooldown, or, with FedCM, the browser's settings decide when it shows.
Match your symptom
| What you see | Most likely cause | Go to |
|---|---|---|
Console: [GSI_LOGGER]: The given origin is not allowed for the given client ID |
Page origin not in Authorized JavaScript origins | Fix 1 |
| Popup shows Error 400: origin_mismatch | Same as above | Fix 1 |
google is not defined / Cannot read properties of undefined (reading 'accounts') |
Your code runs before gsi/client loads |
Fix 2 |
CSP violation in console, or FedCM get() rejects with NetworkError |
Content Security Policy blocks accounts.google.com/gsi/ |
Fix 3 |
FedCM get() rejects with NotAllowedError inside an iframe |
Missing allow="identity-credentials-get" |
Fix 3 |
| Popup opens blank | Cross-Origin-Opener-Policy (when FedCM is off) | Fix 3 |
| Button works, One Tap never appears | HTTPS, cooldown, browser setting, or auto_prompt off |
Fix 4 |
| Click works but your server never gets the credential | popup vs redirect mode mismatch |
Fix 5 |
Fix 1: Add the exact origin to Authorized JavaScript origins
GIS checks the page's origin, not a path. As of Oct 2026, open Google Cloud console → Google Auth Platform → Clients → your Web application client, and under Authorized JavaScript origins add every origin that shows the button:
http://localhost
http://localhost:5173
https://example.com
https://www.example.com
- Google's GIS setup guide says to add both
http://localhostandhttp://localhost:<port>for local testing. - Include the port whenever it isn't the default; an origin with a different port is a different origin.
- No path, query, fragment or trailing slash, and no wildcard (
*). Only localhost may usehttp. wwwand the apex domain are separate entries.- Make sure the
client_idin your page belongs to the client you edited. - Google says changes can take 5 minutes to a few hours to take effect, so retest later before changing more.
Fix 2: Load the library before you call it
Load the script from Google (Google says self-hosting it isn't supported):
<script src="https://accounts.google.com/gsi/client" async></script>
HTML API (no JavaScript needed):
<div id="g_id_onload"
data-client_id="YOUR_CLIENT_ID.apps.googleusercontent.com"
data-callback="handleCredentialResponse"
data-auto_prompt="false">
</div>
<div class="g_id_signin" data-type="standard"></div>
<script>
function handleCredentialResponse(response) {
// response.credential is the ID token (JWT): send it to your server
}
</script>
JavaScript API: because the script is async, wait for it. window.onGoogleLibraryLoad fires after the library loads (it is a shortcut for window.onload):
<div id="buttonDiv"></div>
<script>
window.onGoogleLibraryLoad = () => {
google.accounts.id.initialize({
client_id: "YOUR_CLIENT_ID.apps.googleusercontent.com",
callback: handleCredentialResponse,
});
google.accounts.id.renderButton(
document.getElementById("buttonDiv"),
{ theme: "outline", size: "large" }
);
google.accounts.id.prompt(); // optional: also request One Tap
};
</script>
Don't mix the two: Google warns against using g_id_onload / g_id_signin together with the JavaScript API.
React and other SPAs: inject the script once and render after it loads, into an element that exists:
import { useEffect, useRef } from "react";
export function GoogleButton({ onCredential }) {
const ref = useRef(null);
useEffect(() => {
const render = () => {
window.google.accounts.id.initialize({
client_id: import.meta.env.VITE_GOOGLE_CLIENT_ID, // Vite; use your framework's env access
callback: (res) => onCredential(res.credential),
});
window.google.accounts.id.renderButton(ref.current, {
theme: "outline",
size: "large",
width: 300, // pixels, maximum 400
});
};
if (window.google?.accounts?.id) return render();
let script = document.querySelector('script[src="https://accounts.google.com/gsi/client"]');
if (!script) {
script = document.createElement("script");
script.src = "https://accounts.google.com/gsi/client";
script.async = true;
document.head.appendChild(script);
}
script.addEventListener("load", render, { once: true });
return () => script.removeEventListener("load", render);
}, [onCredential]);
return <div ref={ref} />;
}
This component uses only the documented initialize and renderButton calls. Test this on a preview deployment before relying on it.
Fix 3: Allow GIS in your CSP and headers
If you send a Content Security Policy, add Google's documented sources:
Content-Security-Policy:
script-src 'self' https://accounts.google.com/gsi/client;
frame-src https://accounts.google.com/gsi/;
connect-src 'self' https://accounts.google.com/gsi/;
style-src 'self' https://accounts.google.com/gsi/style;
If you rely on default-src, add https://accounts.google.com/gsi/ there. Google notes that without the right CSP, the FedCM One Tap or button won't display, and a blocked connect-src shows up as FedCM get() rejects with NetworkError.
Other headers:
- Referrer-Policy: Google recommends
strict-origin-when-cross-origin; for localhttptesting it documentsno-referrer-when-downgrade. - Cross-Origin-Opener-Policy: only when FedCM is disabled, use
same-origin-allow-popups; otherwise the popup can open blank. - Iframes: if the button or One Tap runs in a cross-origin iframe, add
allow="identity-credentials-get"to every parent iframe:
<iframe src="https://login.example.com/widget" allow="identity-credentials-get"></iframe>
Fix 4: One Tap not showing
Work through these in order:
- HTTPS. Serve the page over HTTPS (localhost is the exception for testing). Google's JavaScript reference lists
secure_http_requiredamong the reasons One Tap is not displayed. - Is it requested? One Tap appears only if you call
google.accounts.id.prompt()or leavedata-auto_prompton.data-auto_prompt="false"turns it off. - Cooldown after closing. Without FedCM, each close suppresses One Tap for longer: two hours, then one day, one week, and four weeks. A successful sign-in with One Tap or the button resets it. With FedCM, browser vendors may set their own cooldown; Google says Chrome users can reset it from the lock icon in the address bar → Reset Permission (the icon can look different in newer Chrome versions).
- Chrome's third-party sign-in setting. With FedCM, One Tap needs the browser's Third-party sign-in setting allowed (globally or for your site). Google notes this affects One Tap, not the button.
- Browsers with Intelligent Tracking Prevention. Google lists Safari, Firefox and Chrome on iOS: they show a different One Tap flow (welcome page, then a popup), automatic sign-in isn't supported, and the upgraded flow needs
itp_support: true. - No Google session. If nobody is signed in to Google in that browser, there is no account to offer in One Tap. Keep the button as a visible fallback.
- Outdated code. With FedCM, Google says the
isDisplayMoment(),isDisplayed(),isNotDisplayed()andgetNotDisplayedReason()notifications are not supported, andgetSkippedReason()no longer gives a detailed reason. Code that waits for those callbacks before showing a fallback will never fire.use_fedcm_for_promptis deprecated and ignored, so removing it is harmless. - After sign-out, call
google.accounts.id.disableAutoSelect()so automatic sign-in doesn't loop.
Fix 5: Popup mode vs redirect mode
ux_mode: "popup" (default) |
ux_mode: "redirect" |
|
|---|---|---|
| Where the credential goes | Your JavaScript callback |
POSTed to login_uri |
| Required setting | callback (popup mode doesn't support redirects) |
login_uri: absolute https URI (http only on localhost) |
| Google Cloud entry | Authorized JavaScript origin | JavaScript origin and the login_uri under Authorized redirect URIs |
ux_mode has no effect on One Tap. Set either callback or login_uri, not both: Google's One Tap guide says you can't set both, and its button guide says data-callback takes precedence if you do. For a redirect_uri_mismatch in redirect mode, see redirect_uri_mismatch explained.
How to confirm it worked
- The button renders and the console has no
[GSI_LOGGER]or CSP errors. - Clicking it, choosing an account, and returning calls your
callbackwithresponse.credential(or POSTs it tologin_uri). - Your server validates that ID token: Google signature,
audequal to your client ID,issofaccounts.google.comorhttps://accounts.google.com, and an unexpiredexp. In Node.js,OAuth2Client.verifyIdTokenfromgoogle-auth-librarychecks all four. - Test One Tap in a fresh browser profile where you haven't closed it before.
Related problems
FAQ
Why is my Google sign-in button not showing at all?
Check the console first. The given origin is not allowed for the given client ID means the page's exact origin (including port) is missing from Authorized JavaScript origins. No error usually means your code ran before gsi/client loaded, or a CSP blocked it.
Why does One Tap show on one of my domains but not another?
One Tap may not display on a page that isn't served over HTTPS, and each origin needs its own Authorized JavaScript origin entry. With FedCM, Chrome users can also allow or block third-party sign-in prompts per site, so one domain can be blocked while another is allowed.
How do I reset the One Tap cooldown while testing?
A successful sign-in with One Tap or the button resets it. With FedCM in Chrome, Google says to click the lock icon in the address bar and select Reset Permission; a new browser profile also works.
Can I self-host or bundle the gsi/client script?
No. Google's setup guide says to load https://accounts.google.com/gsi/client on each page where users might sign in and that self-hosting it isn't supported. If your CSP blocks that request, the button can't render (see Fix 3).
What is Error 400: origin_mismatch?
Google returns it when a request comes from a JavaScript origin that isn't registered on the OAuth client. Add the exact origin and wait for the change to apply.
Sources
- Setup | Sign In With Google for Web | Google for Developers
- Display the Sign In With Google button | Google for Developers
- Display Google One Tap | Google for Developers
- Understand the One Tap user experience | Google for Developers
- Migrate to FedCM | Google for Developers
- Sign In With Google JavaScript API reference | Google for Developers
- Verify the Google ID token on your server side | Google for Developers
- Manage OAuth Clients | Google Cloud Platform Console Help
- Sign in with Google ends with "[GSI_LOGGER]: The given origin is not allowed for the given client ID" | Google Developer forums
How this page was made: drafted with AI from the sources listed, reviewed by Pewterkit. Docs checked Oct 27, 2026. Spotted something out of date? Tell us.
Related guides
- "Access blocked: This app's request is invalid" - find the real error and fix it
- "Error 400: invalid_request" on Google sign-in: read the details and fix the cause
- "Access blocked: app has not completed the Google verification process" - why and how to fix it
- Google OAuth consent screen: setup, Internal vs External, and why it isn't showing