Google sign in
From an empty Google Cloud project to a working Google button, with the exact addresses to paste and what each error means.
Two names, GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET, and roughly ten minutes in the Google Cloud
console. Both names are read by the deployment, not by the app.
Which of the two Google flows is this
This is sign in: somebody uses their Google account instead of a password, and the installation learns their email address. It is not a Gmail connection and it asks for no access to anybody's mail, files or calendar. The only things requested are the identity claims: who they are and their address.
Before you start, know your two addresses
Have these two in front of you. Every paste below is one of them.
| What | On a laptop | On a server |
|---|---|---|
The app's address, which is SITE_URL | http://localhost:3000 | https://loomis.your-domain.com |
| The deployment's site URL | printed by npx convex dev | shown in the Convex dashboard |
The deployment's site URL looks like https://quick-fox-1234.convex.site. Both addresses stay usable at the
same time, which is what makes local development work against the same Google client.
The walkthrough
Create a project
Go to console.cloud.google.com, open the project picker at the top, choose New project, name it after your product, and create it.
A company that already has a Workspace account can put this project inside that organisation instead, which is a better idea if the product belongs to the company rather than to you personally.
The consent screen
APIs & Services → OAuth consent screen. Four fields matter:
| Field | What to put |
|---|---|
| User type | External, or Internal if the installation is only for your Workspace |
| App name | The name of your product, which is what people see on the consent page |
| User support email | An address people can write to if they are confused |
| Developer contact | Your address, for Google to reach you |
Save and continue. On the scopes step, the defaults are enough: openid, the email claim and the basic
profile claim. All three are non-sensitive, which means no review and no verification delay.
External and still in testing
While the app is in Testing, only the accounts you list as test users can sign in, and the others are refused with a message that says the app is not configured for them. Add yourself and anybody who needs to try it, or press Publish app when you are ready for everybody. Publishing with only these three scopes needs no review.
The client
APIs & Services → Credentials → Create credentials → OAuth client ID, and choose Web application as the type. This is the only type that can hold a redirect address, which is what this flow needs.
Authorized JavaScript origins:
http://localhost:3000
https://loomis.your-domain.comAuthorized redirect URIs, both of them, one per line:
http://localhost:3000/api/auth/callback/google
https://loomis.your-domain.com/api/auth/callback/google
https://quick-fox-1234.convex.site/api/auth/callback/googleWhy two callback addresses and not one
The app forwards every authentication request to the deployment, where the account functions live, and
either address can be the one Google hands the answer back to depending on which one the request arrived
at. Google allows a list here, so the safe answer is to list both. Replace quick-fox-1234 with your own
deployment's name, from the address npx convex dev printed.
Copy the two values
The dialog shows the client ID and the client secret. The secret is shown once, and it is the only value in this page that is actually secret. Copy both.
A client secret is not a client ID
The ID ends in .apps.googleusercontent.com and is public. The secret starts with GOCSPX-. They are
pasted into two different fields, and swapping them produces a sign-in that redirects correctly and then
fails with no useful message.
Set them on the deployment
npx convex env set GOOGLE_CLIENT_ID "1234567890-abcdef.apps.googleusercontent.com"
npx convex env set GOOGLE_CLIENT_SECRET "GOCSPX-your-secret"Add --prod when you are configuring the production deployment. Set both, in the same environment: the
pair is read together and a half-configured provider is treated as unconfigured.
Try it
Open /sign-in, press Google, and pick an account. The consent screen appears, you are returned to the
installed app, and you land signed in.
If the installation is set to invite-only in System → Security, a Google sign in for an unknown address
is refused after the consent screen, with the reason. That is the policy working, not the provider failing.
When it does not work
Turning it off later
Delete the two names from the deployment's environment and the button goes back to saying the provider is not configured:
npx convex env unset GOOGLE_CLIENT_ID
npx convex env unset GOOGLE_CLIENT_SECRETAccounts that were created through Google still exist and still have their data. They can be given a password by the person who owns them through the reset flow, as long as mail is configured.

