Notes

"The given origin is not allowed for the given client ID":Sign In With Google and JavaScript origins

Google OAuth redirect_uri_mismatch Doctor

You add a Sign In With Google button or One Tap to a page, and sign-in does not work. In the reports cited below, the button failed to load or the Google window kept coming back without signing anyone in. The browser console has one line:

[GSI_LOGGER]: The given origin is not allowed for the given client ID.

Google Identity Services, the library you load from accounts.google.com/gsi/client, only works on pages whose origin is listed under Authorized JavaScript origins on the OAuth client whose ID you passed in. An origin is three things: scheme, host and port. If no entry in that list matches all three, you get this line. In one of the Stack Overflow questions below it came together with a 403 on accounts.google.com/gsi/status?client_id=..., so the Network tab is worth a look too.

This is a different list from Authorized redirect URIs. If Google shows you Error 400: redirect_uri_mismatch instead, that one is covered in the note on redirect_uri_mismatch, and changing redirect URIs does nothing for this message. Below: what Google compares, the causes in the order people tend to hit them, the fix, and how to confirm it.

What Google compares

Google's setup guide says an entry in Authorized JavaScript origins "includes the scheme and fully qualified hostname only", for example https://www.example.com. MDN's definition of an origin adds the port: two URLs have the same origin only when the scheme, the hostname and the port all match. The path, the query string and anything after # never take part. To see the exact origin of your page, open the console on the page with the button and ask the browser:

Browser console, on the page with the button

location.origin
// "http://localhost:5173"
Which part of the page address Google checks, and which list entries match it The page address http://localhost:5173/login?next=/app splits into scheme http, host localhost, port 5173, and a path and query that never take part in the check. The origin Google checks is http://localhost:5173, the value of location.origin. Entries in Authorized JavaScript origins that do not match: http://127.0.0.1:5173 has a different host, and one report says 127.0.0.1 fails even when it is listed; https://localhost:5173 has a different scheme; http://localhost:5174 has a different port, as when Vite takes the next free port. Not a valid entry at all: http://localhost:5173/ has a path, which Google's rules do not allow in an origin, so the Console rejects it instead of saving it. What makes it match: the exact entry http://localhost:5173, plus the port-less http://localhost that Google asks for in local development. Both go on the Web application client whose ID the page sends. THE PAGE WHERE THE BUTTON RUNS http:// localhost :5173 /login?next=/app scheme host port path, query the path and the query never take part in the check THE ORIGIN GOOGLE CHECKS http://localhost:5173 location.origin scheme, host and port must all equal one entry ENTRIES THAT DO NOT MATCH http:// 127.0.0.1 :5173 different host a different host; reported to fail even when listed https:// localhost :5173 different scheme the dev server serves http, the entry says https http:// localhost :5174 different port Vite took the next free port because 5173 was busy NOT A VALID ENTRY http:// localhost :5173 / rejected on save a trailing / is a path; the Console will not save it WHAT MAKES IT MATCH http:// localhost :5173 match the exact origin of the page http:// localhost add it too Google's key point for local development Both go on the Web application client whose ID your page sends in data-client_id or client_id.
Google checks the scheme, host and port of the page, never its path. The three rows that fail each differ from http://localhost:5173 in one part. The entry with a trailing slash never reaches your list: Google's rules do not allow a path in an origin, and the Console rejects it when you save. The rules come from Google's setup guide and its JavaScript origin validation rules, the port behavior from Vite's server options, the port-less localhost entry from the guide's key point for local development, and the 127.0.0.1 and trailing-slash reports from Stack Overflow. All are cited below.

Google's JavaScript origin validation rules also limit what an entry may contain: https for everything except localhost, no raw IP addresses except localhost ones, no path, no query, no fragment, and no wildcard characters. RFC 3986 counts the / right after the host as a path, so an origin copied from the address bar with a trailing slash is not a valid entry. The Console will not save it, so it cannot be the entry that fails in a list you already saved: look at scheme, host and port there.

01

Localhost with a port, and no entry without it

This is the accepted answer, with over 500 votes, on the most viewed question about this error (about 139,000 views). The asker's page ran on http://localhost:8080, the older gapi library worked there, and GSI refused it until the origin without the port was added too. Google's setup guide states it as a key point: for local tests or development, add both http://localhost and http://localhost:<port_number>.

Authorized JavaScript origins, local development

http://localhost
http://localhost:5173

Use the port your dev server actually prints. Vite starts on 5173, but its docs say that if the port is in use it "will automatically try the next available port", so the origin you registered yesterday may not be today's. Setting server.strictPort: true makes Vite exit instead of moving.

02

The page runs on a different host than the entry

MDN lists http://example.com and http://www.example.com as different origins, and Google compares strings, not machines. Three versions show up again and again:

  • 127.0.0.1 instead of localhost. Two answers on the main question, both from people using VS Code's Live Server, report that 127.0.0.1 kept failing and the error went away once they switched Live Server's host setting to localhost. One of them, with 29 votes, says 127.0.0.1 did not work even when it was registered. So do not stop at registering 127.0.0.1: open the page on localhost and register localhost, which is also what Google's guide names.
  • www and the bare domain. One answer needed both https://example.com and https://www.example.com in the list. Register every host that can load the page, or redirect to one of them before the page with the button loads.
  • A LAN address, to test on a phone. http://192.168.1.20:5173 cannot be registered at all: the rules forbid raw IP addresses other than localhost ones, and plain http outside localhost. Use a real hostname served over https.

03

Staging or production on plain http

One question below describes it exactly: sign-in worked on localhost, and the staging server, registered as http://stg..., returned 403 on gsi/status with this message. Google's rules require the https scheme for every JavaScript origin except localhost, and the setup guide adds that One Tap can only be displayed on HTTPS domains. An answer on the main question gives the same fix: outside localhost, serve the site over https.

Before: http://stg.example.com
After:  https://stg.example.com

04

A Referrer-Policy that hides your origin

Google's setup guide notes that loading gsi/client from accounts.google.com is a cross-origin request and recommends Referrer-Policy: strict-origin-when-cross-origin. For testing over http on localhost it says to use no-referrer-when-downgrade. An answer with 51 votes on the main question reports that with no-referrer, the requests to gsi/button and gsi/iframe/select fail with 400 and this exact message. Two common server defaults are stricter than Google's recommendation:

  • Helmet sets Referrer-Policy: no-referrer by default, which per MDN sends no referrer information at all.
  • Django sets SECURE_REFERRER_POLICY to 'same-origin' by default, and MDN says that policy sends no Referer header on cross-origin requests. An answer on the Django question below fixed One Tap on localhost with no-referrer-when-downgrade.

Express with Helmet

app.use(helmet({
  referrerPolicy: { policy: 'strict-origin-when-cross-origin' },
}));

Django, settings.py

# Google's recommendation for gsi/client over https
SECURE_REFERRER_POLICY = "strict-origin-when-cross-origin"
# Google's key point for testing over http on localhost:
# SECURE_REFERRER_POLICY = "no-referrer-when-downgrade"

A policy can also come from a <meta name="referrer"> tag in the HTML, which MDN documents as a second way to set it. Search your templates for one before you decide the header is fine.

05

The client ID is not the client you edited

The list belongs to one OAuth client. Google's guide says to use a client of type Web application and to put its ID in your page through data-client_id or client_id. The usual mix-ups: a production build that reads a client ID from another Google Cloud project, the right-looking client edited in the wrong project, or a client of another type. On the older question about the previous library, one answer found a trailing space inside the client ID string.

The ID the page sends is the one Google checks

google.accounts.id.initialize({
  client_id: 'YOUR_CLIENT_ID.apps.googleusercontent.com',
  callback: handleCredentialResponse,
});

Fix: read the ID from the page itself, not from your notes. The request to accounts.google.com/gsi/status in the report above carried it in its URL as client_id=. Open exactly that client on the Clients page of Google Cloud Console.

06

You just saved, and nothing has changed yet

Google Cloud's help page on OAuth clients says: "It may take 5 minutes to a few hours for changes made to these settings to take effect". On the older question about the previous library, the most voted answer (277 votes) was simply clearing the browser cache after the change. So after you save a correct entry, wait, then test in a new private window before you change anything else. Changing three things at once during the delay is how a correct fix gets undone.

The older message: idpiframe_initialization_failed

The same problem on the older Google Sign-In JavaScript library looked like this, in a 2017 question with about 158,000 views: idpiframe_initialization_failed with "Not a valid origin for the client". It is the same Authorized JavaScript origins list and the same fixes. Google deprecated that library as of March 31, 2023, and new OAuth client IDs cannot use it. Only client IDs created before July 29, 2022 may. If you are still on it, the migration to Google Identity Services is the real fix.

Fix it, in order

  1. On the page with the button, run location.origin in the console and copy the result exactly.
  2. In the Network tab, find a request to accounts.google.com/gsi/ and read its client_id. That is the client Google checks, whatever your config file says. If you see no such request, read data-client_id in the Elements panel, or log the value your code passes to initialize. Google's FedCM migration guide says that with FedCM the browser shows the prompts itself and contacts Google only after the user consents, so a current browser may not make the same requests as the 2021 and 2022 reports.
  3. Open the Clients page in Google Cloud Console, in the project that owns that client ID, and open that Web application client.
  4. Under Authorized JavaScript origins, add the origin from step 1 character for character: no path, no trailing slash. On localhost, add the port-less http://localhost as well.
  5. Save. Then check the Referrer-Policy of your page: select the document request in the Network tab, read its response headers, and look for a <meta name="referrer"> tag.
  6. Wait a few minutes and test in a new private window.

Confirm the fix

  • The console is clean. After a fresh load, the [GSI_LOGGER] line no longer appears.
  • The requests pass. In the Network tab, the requests to accounts.google.com/gsi/ that you do see no longer come back with 403 or 400.
  • A credential arrives. The button renders, and after you pick an account your callback runs. Google's reference says the callback receives a response whose credential field is the ID token.
  • Every origin works. Repeat on each origin that serves the page: localhost, staging, production, and both www and the bare domain if both load it.

Temporary check in the callback

function handleCredentialResponse(response) {
  // true means Google returned an ID token; do not log the token itself
  console.log('credential received:', Boolean(response.credential));
}

Traps

  • Editing Authorized redirect URIs. Google's guide asks for redirect URIs only when the credential is returned "using a redirect to an endpoint you host rather than through a JavaScript callback". The API references spell out when that is: a POST to login_uri, which with the JavaScript API happens only in the button's redirect UX mode, and with the HTML API also for One Tap and the popup button when no data-callback is set. Then login_uri must exactly match one of the redirect URIs. The origin list is still checked either way: the asker of the most viewed question below used data-login_uri with no callback, and the accepted fix was an origin entry.
  • A trailing slash from the address bar. https://example.com/ has a path, and Google's rules do not allow a path in an origin. The Console refuses to save it (in one question it said origin URIs "must not contain a path or end with" a slash), so if saving fails, drop the slash. If your list saved, a trailing slash is not what fails.
  • A wildcard for preview deploys. The rules do not allow wildcard characters. Add each preview origin you test with, or test sign-in on a fixed domain.
  • Loosening Cross-Origin-Opener-Policy to fix this line. The COOP section of Google's guide is about popups: a wrong COOP leads to "a blank pop-up window or similar bugs", which is a different symptom. It also matters only when FedCM is disabled: "When FedCM is enabled the browser directly renders popups and no changes are necessary." Leave COOP alone unless that is what you see.

Compare your origin with the list

The Google OAuth redirect_uri_mismatch Doctor is built for redirect_uri_mismatch, and it has one check that fits this error. This link opens it with an example for this error only: http://localhost:5173 in App origin, and http://localhost and http://127.0.0.1:5173 in Authorized JavaScript origins. Replace them with your location.origin and your own list, one origin per line, and press Diagnose. If your origin is missing, the tool says so and gives the entry to add. It calls the error by its older names, invalid_origin and "not a valid origin for the client", not by the [GSI_LOGGER] text. If your origin is in the list, it says nothing about the origin at all. It will also report that the redirect_uri field is empty, which you can ignore for this error, and its Reset button brings back its own Supabase example rather than an empty form. It does not check the port-less localhost entry or your Referrer-Policy. The tool page states that nothing you paste leaves your browser.

Questions

I added the origin and still see the error. What now?

Wait first. Google's help page on OAuth clients says changes to these settings can take 5 minutes to a few hours to take effect. Then load the page in a new private window. If it still fails, compare location.origin on the page with the list again, add the port-less http://localhost if you are on localhost, and check that the client_id in the request to accounts.google.com is the client you edited.

Do I also need an Authorized redirect URI for Sign In With Google?

Only when Google POSTs the credential to your server through login_uri, which defaults to the current page. With the JavaScript API that happens only in the button's redirect UX mode. With the HTML API it also happens for One Tap and the popup button when no data-callback is set, as in the most viewed question below. In those cases login_uri must exactly match one of the Authorized redirect URIs. With a JavaScript callback you need no redirect URI. The origin list is checked either way, so adding redirect URIs does not fix this message.

Can I use a wildcard for Vercel or Netlify preview URLs?

No. Google's JavaScript origin validation rules do not allow wildcard characters. Add each preview origin you want to test with, or test sign-in on a fixed domain.

Sign-in works on localhost but not on my staging server. Why?

Usually one of three things. Staging is served over plain http, which Google only allows for localhost. The staging host in the list differs from the one in the address bar, www against the bare domain for example. Or the server sends a Referrer-Policy that localhost did not, such as Helmet's default no-referrer or Django's default same-origin.

Is this the same problem as origin_mismatch or idpiframe_initialization_failed?

It is the same list. Google documents origin_mismatch for the OAuth 2.0 flow in client-side web apps, when the scheme, domain or port of the page does not match an authorized JavaScript origin. idpiframe_initialization_failed with "Not a valid origin for the client" came from the older Google Sign-In JavaScript library, which is deprecated and cannot be used with new client IDs.

Sources

  • Google for Developers, "Get your Google API client ID" (Sign In With Google for Web: a client of type Web application; an origin entry "includes the scheme and fully qualified hostname only"; add both http://localhost and http://localhost:<port_number> for local tests; One Tap only on HTTPS domains; the client ID goes in data-client_id or client_id; redirect URIs only when the credential is returned through a redirect; strict-origin-when-cross-origin recommended because loading gsi/client is cross-origin, no-referrer-when-downgrade when testing over http on localhost): developers.google.com/identity/gsi/web/guides/get-google-api-clientid; the same page, "Cross Origin Opener Policy" (a wrong COOP leads to a blank pop-up window; when FedCM is enabled no COOP changes are necessary): #cross_origin_opener_policy
  • Google for Developers, "Migrate to FedCM" (with FedCM the browser displays the user prompts and contacts Google only after explicit user consent): developers.google.com/identity/gsi/web/guides/fedcm-migration
  • Google for Developers, "Using OAuth 2.0 for Client-side Web Applications", "JavaScript origin validation rules" (https except localhost, no raw IP addresses except localhost ones, no userinfo, path, query or fragment, no wildcard characters): developers.google.com/identity/protocols/oauth2/javascript-implicit-flow#origin-validation; the origin_mismatch error (scheme, domain and/or port do not match an authorized JavaScript origin): #authorization-errors-origin-mismatch
  • Google for Developers, "Sign In With Google JavaScript API reference" (google.accounts.id.initialize, client_id, callback; login_uri must exactly match one of the authorized redirect URIs and is only used when ux_mode is redirect; with the JavaScript API, One Tap and the popup UX mode return the response only to the callback; the credential field of CredentialResponse is the ID token): developers.google.com/identity/gsi/web/reference/js-reference
  • Google for Developers, "Sign In With Google HTML API reference", data-login_uri (must exactly match one of the authorized redirect URIs; defaults to the current page; the credential is posted there "when no callback function is defined and a user clicks on the Sign In With Google or One Tap buttons, or automatic sign takes place") and data-callback (one of the two must be set for One Tap and the popup UX mode; the redirect UX mode requires data-login_uri): developers.google.com/identity/gsi/web/reference/html-reference#data-login_uri
  • Google for Developers, "Google Sign-In JavaScript library deprecation" (deprecated as of March 31, 2023; new OAuth client IDs cannot use the deprecated library; client IDs created before July 29, 2022 may): developers.google.com/identity/sign-in/web/deprecation-and-sunset
  • Google Cloud Platform Console Help, "Manage OAuth Clients" ("It may take 5 minutes to a few hours for changes made to these settings to take effect"): support.google.com/cloud/answer/15549257
  • MDN, "Origin" (scheme, hostname and port; example.com and www.example.com are different origins): developer.mozilla.org/en-US/docs/Glossary/Origin; Location.origin: developer.mozilla.org/en-US/docs/Web/API/Location/origin; Referrer-Policy (no-referrer, same-origin, strict-origin-when-cross-origin, no-referrer-when-downgrade, and the <meta name="referrer"> element): developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Referrer-Policy
  • RFC 3986, URI Generic Syntax, section 3.3 "Path" (path-abempty = *( "/" segment ), so a / after the host is a path): rfc-editor.org/rfc/rfc3986#section-3.3
  • Helmet, "Referrer-Policy" (default no-referrer; the referrerPolicy option with policy): helmet.js.org/#referrer-policy
  • Django, settings, SECURE_REFERRER_POLICY (default 'same-origin'): docs.djangoproject.com/en/stable/ref/settings/#secure-referrer-policy
  • Vite, "Server Options" (server.port defaults to 5173 and moves to the next available port when it is in use; server.strictPort): vite.dev/config/server-options#server-strictport
  • Stack Overflow, "The given origin is not allowed for the given client ID (GSI)" (2021, about 139,000 views; http://localhost:8080 with gapi working and GSI failing, the asker's HTML sets data-login_uri and no data-callback; the accepted answer with over 500 votes adds the origin without the port; an answer with 51 votes on no-referrer and Helmet; two answers on Live Server and 127.0.0.1, one with 29 votes saying 127.0.0.1 did not work even when registered; an answer needing both www and the bare domain; an answer on https outside localhost): stackoverflow.com/questions/68438293
  • Stack Overflow, "[GSI_LOGGER]: The given origin is not allowed for the given client ID" (2021, about 11,500 views; Django and One Tap on localhost; an answer setting SECURE_REFERRER_POLICY = "no-referrer-when-downgrade"): stackoverflow.com/questions/68854740
  • Stack Overflow, "Google OAuth [GSI_LOGGER]: The given origin is not allowed for the given client ID" (2022, about 8,500 views; localhost works, a staging server registered over http fails with 403 on gsi/status?client_id=...): stackoverflow.com/questions/74385278
  • Stack Overflow, "Google API: Not a valid origin for the client" (2017, about 158,000 views; idpiframe_initialization_failed on the older library; the most voted answer, 277 votes, cleared the browser cache; another answer found a trailing space in the client ID): stackoverflow.com/questions/43964539
  • Stack Overflow, "Authorized JavaScript origins not working localhost" (2017, about 12,000 views; the Console refused http://localhost/charts/ with "Origin URIs must not contain a path or end with "/""): stackoverflow.com/questions/46957780