#convex auth doesnt work google oauth
23 messages · Page 1 of 1 (latest)
Hi @regal garnet. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:
If Convex Auth is not working with Google OAuth, there are a few common issues and troubleshooting steps based on the knowledge sources:
-
Callback URL Configuration
Make sure your Google OAuth client is configured with the correct callback URL. For Convex, this should be your deployment's HTTP Actions URL plus/api/auth/callback/google. For example:<https://your-deployment.convex.site/api/auth/callback/google>If you are using a custom domain in production, set the
CUSTOM_AUTH_SITE_URLenvironment variable in your Convex dashboard to match your custom domain, and update your OAuth provider's callback URL accordingly. Otherwise, Google will show your.convex.sitedomain on the consent screen, which may not be desirable for production apps.
Custom callback and sign-in URLs
Google OAuth setup instructions -
Environment Variables
Ensure that you have set theAUTH_GOOGLE_IDandAUTH_GOOGLE_SECRETenvironment variables in your Convex project. You can do this via the Convex dashboard or using the CLI:npx convex env set AUTH_GOOGLE_ID <your-google-client-id> npx convex env set AUTH_GOOGLE_SECRET <your-google-client-secret>
-
Provider Configuration
In yourconvex/auth.ts, make sure you are importing and using the Google provider correctly:import Google from "@auth/core/providers/google"; import { convexAuth } from "@convex-dev/auth/server"; export const { auth, signIn, signOut, store, isAuthenticated } = convexAuth({ providers: [Google], }); -
Common Errors and Debugging
- If you see an "Invalid verifier" error, this may be a bug in Convex Auth, especially if the session does not persist after login. This issue has been reported by multiple users and may not have a straightforward fix yet. Enabling verbose logging and sharing a minimal reproduction with Convex support can help them diagnose the issue further.
Discussion of "Invalid verifier" error - If
getAuthUserId(ctx)returnsnulleven after successful sign-in, double-check that your environment variables (likeCONVEX_SITE_URL) are set correctly and not undefined, as this can block JWT validation and prevent authentication from working.
getAuthUserId returns null troubleshooting
- If you see an "Invalid verifier" error, this may be a bug in Convex Auth, especially if the session does not persist after login. This issue has been reported by multiple users and may not have a straightforward fix yet. Enabling verbose logging and sharing a minimal reproduction with Convex support can help them diagnose the issue further.
-
Version Compatibility
Ensure you are using the recommended versions of dependencies. For example, some users have reported issues with newer versions of@auth/coreand resolved them by installing the exact supported version:npm install @auth/[email protected] --save-exact
If you have followed all the setup steps and are still experiencing issues, it may be a bug in Convex Auth (which is still in beta). In that case, providing a minimal reproduction to the Convex team or checking for updates in the relevant GitHub issues and Discord threads is recommended.
If you need more specific help, please provide error messages or logs, and double-check your callback URLs and environment variable setup.
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
@regal garnet Kapa.ai is still learning and improving, please let me know how I did by reacting below.
bun convex dev
Found multiple CONVEX_URL environment variables in .env.local so cannot update automatically.
✔ 00:31:56 Convex functions ready! (3.28s)
11/3/2025, 12:31:59 AM [CONVEX H(GET /api/auth/signin/google)] [ERROR] 'Missing sign-in verifier\n at <anonymous> (../../node_modules/@convex-dev/auth/src/server/implementation/index.ts:250:31)\n at <anonymous> (../../node_modules/@convex-dev/auth/src/server/implementation/index.ts:690:20)\n at invokeFunction (../../node_modules/convex/src/server/impl/registration_impl.ts:80:28)\n at invokeHttpAction (../../node_modules/convex/src/server/impl/registration_impl.ts:453:0)\n at e.invokeHttpAction [as invokeHttpAction] (../../node_modules/convex/src/server/impl/registration_impl.ts:464:33)\n at <anonymous> (../../node_modules/convex/src/server/router.ts:328:16)'
@supple thicket bun convex dev
Found multiple CONVEX_URL environment variables in .env.local so cannot update automatically.
✔ 00:31:56 Convex functions ready! (3.28s)
11/3/2025, 12:31:59 AM [CONVEX H(GET /api/auth/signin/google)] [ERROR] 'Missing sign-in verifier\n at <anonymous> (../../node_modules/@convex-dev/auth/src/server/implementation/index.ts:250:31)\n at <anonymous> (../../node_modules/@convex-dev/auth/src/server/implementation/index.ts:690:20)\n at invokeFunction (../../node_modules/convex/src/server/impl/registration_impl.ts:80:28)\n at invokeHttpAction (../../node_modules/convex/src/server/impl/registration_impl.ts:453:0)\n at e.invokeHttpAction [as invokeHttpAction] (../../node_modules/convex/src/server/impl/registration_impl.ts:464:33)\n at <anonymous> (../../node_modules/convex/src/server/router.ts:328:16)'
Let me check the knowledge base for you again. One moment! :books:
The error message you're seeing—"Found multiple CONVEX_URL environment variables in .env.local so cannot update automatically"—indicates that your .env.local file contains more than one environment variable related to the Convex deployment URL. This can cause confusion for the Convex CLI and your application, as it won't know which URL to use.
Additionally, the error "Missing sign-in verifier" during the Google OAuth sign-in flow suggests that the authentication process is not able to complete, likely due to misconfiguration in your environment variables.
How to Fix
-
Check Your
.env.localFile- Make sure you only have one Convex deployment URL variable for your frontend. For Next.js, it should be:
NEXT_PUBLIC_CONVEX_URL=<https://your-deployment.convex.cloud> - Remove any duplicate or similarly named variables like
CONVEX_URL,PUBLIC_CONVEX_URL, etc., unless they are specifically required for another part of your stack. The Convex CLI checks for multiple variables and will not update automatically if it finds more than one (Discord thread on multiple CONVEX_URLs).
- Make sure you only have one Convex deployment URL variable for your frontend. For Next.js, it should be:
-
Restart Your Dev Server
- After cleaning up your
.env.local, restart your development server to ensure the correct environment variable is loaded.
- After cleaning up your
-
Verify OAuth Configuration
- Double-check that your Google OAuth callback URL matches the one configured in your Google Cloud project. It should be:
<https://your-deployment.convex.site/api/auth/callback/google> - Ensure your Convex environment variables for Google OAuth (
AUTH_GOOGLE_IDandAUTH_GOOGLE_SECRET) are set correctly in the Convex dashboard or via the CLI (Google OAuth setup instructions).
- Double-check that your Google OAuth callback URL matches the one configured in your Google Cloud project. It should be:
-
Check for Other Environment Variables
- Make sure
SITE_URLis set if required, especially for OAuth flows (Manual setup instructions).
- Make sure
Summary
- Remove duplicate Convex URL variables from
.env.local. - Ensure only the correct variable (e.g.,
NEXT_PUBLIC_CONVEX_URLfor Next.js) is present. - Restart your dev server.
- Double-check your OAuth and environment variable setup.
If you continue to see the "Missing sign-in verifier" error after these steps, it may indicate a deeper configuration issue or a bug. In that case, review your OAuth provider setup and Convex Auth integration, and consider enabling verbose logging for more details.
If you need more help, please share your .env.local (with secrets redacted) and relevant configuration files.
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
@regal garnet Kapa.ai is still learning and improving, please let me know how I did by reacting below.
I'm using Better Auth with the @convex-dev/better-auth plugin for Google OAuth authentication.
My setup:
- Frontend: Next.js app on (Vercel)
- Backend: Convex .convex.site)
- Auth proxy: /api/auth/[...all]/route.ts that forwards requests from my domain to Convex Site
Problem: Getting "state_mismatch" error during Google OAuth callback. The OAuth state cookie is not being preserved when the callback is proxied from my domain to
Convex.
I've tried:
- Rewriting Set-Cookie headers to remove domain restrictions in my proxy
- Setting BETTER_AUTH_URL to both my domain and convex.site
- Adding advanced cookie config with crossSubDomainCookies enabled
Questions:
- What's the recommended way to handle OAuth with Better Auth when using the Convex plugin but serving the frontend from a custom domain?
- Should the OAuth flow go through my domain or directly to convex.site?
- How should cookies be configured to work across the proxy?
Code: [paste your /api/auth/[...all]/route.ts and convex/auth.ts config]
Include:
- Your exact setup (domains, hosting)
- What you've tried
- Specific error messages
- Relevant code snippets
The more details, the better help you'll get!
@supple thicket I'm using Better Auth with the @convex-dev/better-auth plugin for Google OAuth authentication.
My setup:
Frontend: Next.js app on (Vercel)
Backend: Convex .convex.site)
Auth proxy: /api/auth/[...all]/route.ts that forwards requests from my domain to Convex Site
Problem: Getting "state_mismatch" error during Google OAuth callback. The OAuth state cookie is not being preserved when the callback is proxied from my domain to
Convex.
I've tried:
Rewriting Set-Cookie headers to remove domain restrictions in my proxy
Setting BETTER_AUTH_URL to both my domain and convex.site
Adding advanced cookie config with crossSubDomainCookies enabled
Questions:
What's the recommended way to handle OAuth with Better Auth when using the Convex plugin but serving the frontend from a custom domain?
Should the OAuth flow go through my domain or directly to convex.site?
How should cookies be configured to work across the proxy?
Code: [paste your /api/auth/[...all]/route.ts and convex/auth.ts config]
Include:
Your exact setup (domains, hosting)
What you've tried
Specific error messages
Relevant code snippets
The more details, the better help you'll get!
Let me check the knowledge base for you again. One moment! :books:
You're encountering a common challenge when using Google OAuth with Better Auth and Convex, especially when your frontend is on a custom domain (e.g., Vercel) and your Convex backend is on a .convex.site domain. The "state_mismatch" error typically means the OAuth state cookie set at the start of the flow is not available on the callback, often due to domain or path mismatches in cookie handling.
1. Should the OAuth flow go through your domain or directly to convex.site?
Recommended:
The OAuth flow (including the callback) should go directly to your Convex .site domain, not proxied through your custom frontend domain. This is because the state cookie is set by Convex on the .convex.site domain, and browsers will not send that cookie to your custom domain, nor vice versa. Proxying the callback through your domain breaks the state/cookie validation, resulting in the "state_mismatch" error.
This is confirmed by support staff:
The request url should be hitting your site url (ends in convex.site) rather than your cloud url (ends in convex.cloud). You should have a baseURL set on either your authClient or your server Better Auth config (but not both) - that’s likely where the incorrect url is being set.
Discord: Better-auth + convex 404
2. How should cookies be configured to work across the proxy?
Key points:
- You cannot reliably share cookies between your custom domain and
.convex.sitedue to browser security restrictions. - The OAuth state cookie must be set and read by the same domain (Convex's
.sitedomain). - Proxying the callback through your domain will not work unless you have full control over cookie forwarding and domain attributes, which is generally not possible with cross-domain cookies.
3. What is the recommended setup?
- Frontend: Your Next.js app can use a proxy for convenience (e.g.,
/api/auth/[...all]), but for OAuth, the callback URL registered with Google must be the Convex.sitedomain (e.g.,<https://your-app.convex.site/api/auth/callback/google>). - Better Auth client: Set the
baseURLto your Convex.sitedomain. - Do not set
BETTER_AUTH_URLto your custom domain for the OAuth flow. - Do not attempt to rewrite cookies or proxy the callback through your domain.
Example: Google OAuth Redirect URI
<https://your-app.convex.site/api/auth/callback/google>
This should be set in your Google Cloud Console and used in your Convex/Better Auth config.
Example: Better Auth client config (Next.js)
export const authClient = createAuthClient({
baseURL: process.env.NEXT_PUBLIC_CONVEX_SITE_URL, // ends with .convex.site
plugins: [convexClient()],
});
4. Custom Domains and Production
If you want to use a custom domain for your Convex backend (e.g., api.yourdomain.com), you must configure a custom domain in Convex and update your OAuth provider's callback URL accordingly. This requires a Convex Pro plan.
5. Summary
- Do not proxy OAuth callbacks through your custom domain.
- Always use the Convex
.sitedomain for OAuth callbacks unless you have set up a Convex custom domain. - Cookies must be set and read by the same domain; cross-domain cookies are not supported for this flow.
- If you need a custom domain for OAuth, set up a Convex custom domain and update your OAuth provider and environment variables accordingly.
If you follow this pattern, the "state_mismatch" error should be resolved.
If you need to share authentication state between your custom domain and Convex, consider using a custom domain for Convex or architecting your app so that all auth flows go through the Convex domain.
If you have further questions, please provide your code snippets and exact domain setup for more targeted help.
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
@regal garnet Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Let me check the knowledge base for you again. One moment! :books:
The error GET <http://localhost:3000/api/auth/callback/google?...> 404 (Not Found) means that your Next.js app does not have a route at /api/auth/callback/google, so when Google redirects back to your app after authentication, it can't find the handler and returns a 404.
With Better Auth and Convex, the Google OAuth callback URL should point to your Convex deployment's .site domain, not your Next.js app's domain. For example, the callback URL should be:
<https://your-app.convex.site/api/auth/callback/google>
This is confirmed in the official Better Auth and Convex documentation:
Social sign-in for React SPAs works the same as with full stack frameworks, but the authorized redirect URI is based on your Convex site URL instead of your application domain.
For example, with Google sign-in, the authorized redirect URI would look like:
<https://adjective-animal-123.convex.site/api/auth/callback/google>
Better Auth React guide
And from the Convex OAuth docs:
The origin (domain) of the callback URL for Convex Auth is your backend's HTTP Actions URL, which you can find on your Convex dashboard. It matches your CONVEX_URL except for the top-level domain being
.siteinstead of.cloud.
For example, if your deployment name wasfast-horse-123, then your HTTP Actions URL would be<https://fast-horse-123.convex.site> and your callback URL for Google would be:
<https://fast-horse-123.convex.site/api/auth/callback/google>
Convex OAuth general setup
What you should do:
- Update your Google OAuth client configuration in the Google Cloud Console to use your Convex
.sitedomain as the callback URL, notlocalhost:3000or your Vercel frontend domain. - Start the OAuth flow from your frontend, but ensure the callback goes to Convex, not your frontend.
- Do not proxy the callback through your frontend—the Convex backend must handle the callback directly.
If you need to proxy /api/auth/[...all] for other reasons, make sure you are not proxying the OAuth callback itself, as this will break the flow and cause 404s or state/cookie issues.