[GH-ISSUE #3781] Google Sign-in not working local developement with expo #27047

Closed
opened 2026-04-17 17:50:55 -05:00 by GiteaMirror · 3 comments
Owner

Originally created by @Zakisb on GitHub (Aug 4, 2025).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/3781

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

Description

Getting "Access blocked: This app's request is invalid" error with "Error 400: redirect_uri_mismatch" when attempting Google OAuth login through BearAuth.

Setup

  • Backend: Express.js with BetterAuth
  • Frontend: Expo (React Native)
  • Authentication Provider: Google OAuth
  • Environment: Development

Steps to Reproduce

  1. Set up Express backend with port 8000. install the better auth package + expo package.
  2. Configure Google OAuth in Google Console with redirect URI: https://localhost:8000/api/auth/callback/google
  3. Create Expo app (SDK 51)
  4. Attempt to login with Google through the mobile app
  5. Error appears: "Access blocked: This app's request is invalid"

Current vs. Expected behavior

Current Behavior

  • Google OAuth shows error: "Error 400: redirect_uri_mismatch"
  • Cannot complete authentication flow

Expected Behavior

  • Google OAuth should redirect back to the app successfully
  • User should be authenticated

Keep in mind that email login is working smoothly without issue.

What version of Better Auth are you using?

"better-auth": "^1.2.12", "@better-auth/expo": "^1.2.12",

Provide environment information

- OS : MacOS 14.0 (23A344)
- Simulator : iPhone 15 pro
- Browser : Chrome

Which area(s) are affected? (Select all that apply)

Client, Backend

Auth config (if applicable)

import { betterAuth } from "better-auth"
export const auth = betterAuth({
  emailAndPassword: {  
    enabled: true
  },
trustedOrigins: [
    // Production & staging schemes
    "gogain-dev://",
    "gogain-staging://",
    "gogain-prod://",
    "gogain://",
    "gogain://*",
    // Frontend URL from environment
    process.env.FRONTEND_URL,
  ].filter(Boolean), // Remove any undefined values
  accountLinking: {
    enabled: true,
    trustedProviders: ["google", "facebook", "apple"],
  },
  socialProviders: {
    google: {
      prompt: "select_account",
      clientId: process.env.GOOGLE_CLIENT_ID,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET,
    },
    apple: {
      clientId: process.env.APPLE_CLIENT_ID,
      clientSecret: process.env.APPLE_CLIENT_SECRET,
    },
    facebook: {
      clientId: process.env.FACEBOOK_CLIENT_ID,
      clientSecret: process.env.FACEBOOK_CLIENT_SECRET,
    },
  },
});


export const authClient = createAuthClient({
  baseURL: `${process.env.EXPO_PUBLIC_API_URL}`,
  plugins: [
    emailOTPClient(),
    expoClient({
      scheme: process.env.EXPO_PUBLIC_APP_SCHEME,
      storagePrefix: process.env.EXPO_PUBLIC_APP_SCHEME,
      storage: SecureStore,
    }),
    inferAdditionalFields({
      user: {
        onboarded: {
          type: "boolean",
          required: false,
        },
      },
    }),
  ],
});


my env Variables locally: Front

EXPO_PUBLIC_API_URL=http://192.168.1.67:8000
EXPO_PUBLIC_APP_NAME="GoGain Fit (Dev)"
EXPO_PUBLIC_APP_SCHEME=gogain-dev

Backend : 
cors 
app.use(
  cors({
    origin: [
      "http://192.168.1.67:3000",
      "http://192.168.1.67:3001",
      "http://192.168.1.67:8081",
      "http://localhost:5173",
      "http://localhost:5174",
      "http://localhost:3000",
      "http://localhost:3001",
      "http://localhost:3004",
      "http://localhost:8081",
      "http://localhost:3004",
      "http://192.168.1.67:3004",
      "expo://",
      "expo://*",
      "exp://",
      "exp://*",
      "exp://192.168.1.67:8081",
      "exp://192.168.1.67:19000",
      "exp://192.168.1.67:19001",
    ],
    methods: ["GET", "POST", "PUT", "DELETE", "PATCH"], // Specify allowed HTTP methods
    credentials: true, // Allow credentials (cookies, authorization headers, etc.)
  })
);

Additional context

Image

I keep getting this in simulator. also check the google config

Image
Originally created by @Zakisb on GitHub (Aug 4, 2025). Original GitHub issue: https://github.com/better-auth/better-auth/issues/3781 ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce ## Description Getting "Access blocked: This app's request is invalid" error with "Error 400: redirect_uri_mismatch" when attempting Google OAuth login through BearAuth. ## Setup - **Backend**: Express.js with BetterAuth - **Frontend**: Expo (React Native) - **Authentication Provider**: Google OAuth - **Environment**: Development ## Steps to Reproduce 1. Set up Express backend with port 8000. install the better auth package + expo package. 2. Configure Google OAuth in Google Console with redirect URI: `https://localhost:8000/api/auth/callback/google` 3. Create Expo app (SDK 51) 4. Attempt to login with Google through the mobile app 5. Error appears: "Access blocked: This app's request is invalid" ### Current vs. Expected behavior ## Current Behavior - Google OAuth shows error: "Error 400: redirect_uri_mismatch" - Cannot complete authentication flow ## Expected Behavior - Google OAuth should redirect back to the app successfully - User should be authenticated Keep in mind that email login is working smoothly without issue. ### What version of Better Auth are you using? "better-auth": "^1.2.12", "@better-auth/expo": "^1.2.12", ### Provide environment information ```bash - OS : MacOS 14.0 (23A344) - Simulator : iPhone 15 pro - Browser : Chrome ``` ### Which area(s) are affected? (Select all that apply) Client, Backend ### Auth config (if applicable) ```typescript import { betterAuth } from "better-auth" export const auth = betterAuth({ emailAndPassword: { enabled: true }, trustedOrigins: [ // Production & staging schemes "gogain-dev://", "gogain-staging://", "gogain-prod://", "gogain://", "gogain://*", // Frontend URL from environment process.env.FRONTEND_URL, ].filter(Boolean), // Remove any undefined values accountLinking: { enabled: true, trustedProviders: ["google", "facebook", "apple"], }, socialProviders: { google: { prompt: "select_account", clientId: process.env.GOOGLE_CLIENT_ID, clientSecret: process.env.GOOGLE_CLIENT_SECRET, }, apple: { clientId: process.env.APPLE_CLIENT_ID, clientSecret: process.env.APPLE_CLIENT_SECRET, }, facebook: { clientId: process.env.FACEBOOK_CLIENT_ID, clientSecret: process.env.FACEBOOK_CLIENT_SECRET, }, }, }); export const authClient = createAuthClient({ baseURL: `${process.env.EXPO_PUBLIC_API_URL}`, plugins: [ emailOTPClient(), expoClient({ scheme: process.env.EXPO_PUBLIC_APP_SCHEME, storagePrefix: process.env.EXPO_PUBLIC_APP_SCHEME, storage: SecureStore, }), inferAdditionalFields({ user: { onboarded: { type: "boolean", required: false, }, }, }), ], }); my env Variables locally: Front EXPO_PUBLIC_API_URL=http://192.168.1.67:8000 EXPO_PUBLIC_APP_NAME="GoGain Fit (Dev)" EXPO_PUBLIC_APP_SCHEME=gogain-dev Backend : cors app.use( cors({ origin: [ "http://192.168.1.67:3000", "http://192.168.1.67:3001", "http://192.168.1.67:8081", "http://localhost:5173", "http://localhost:5174", "http://localhost:3000", "http://localhost:3001", "http://localhost:3004", "http://localhost:8081", "http://localhost:3004", "http://192.168.1.67:3004", "expo://", "expo://*", "exp://", "exp://*", "exp://192.168.1.67:8081", "exp://192.168.1.67:19000", "exp://192.168.1.67:19001", ], methods: ["GET", "POST", "PUT", "DELETE", "PATCH"], // Specify allowed HTTP methods credentials: true, // Allow credentials (cookies, authorization headers, etc.) }) ); ``` ### Additional context <img width="1179" height="2556" alt="Image" src="https://github.com/user-attachments/assets/1fd90006-0a9b-4553-a3db-689f0f2dce1a" /> I keep getting this in simulator. also check the google config <img width="537" height="366" alt="Image" src="https://github.com/user-attachments/assets/2f576106-8d87-4961-ba4d-90e1123dd87a" />
GiteaMirror added the locked label 2026-04-17 17:50:55 -05:00
Author
Owner

@dosubot[bot] commented on GitHub (Aug 4, 2025):

The root cause of the redirect_uri_mismatch error is that Expo apps using BetterAuth for Google OAuth require a custom scheme URI (like gogain-dev://auth/callback/google) as the redirect URI, not a web URL such as https://localhost:8000/api/auth/callback/google. The Expo client and BetterAuth construct the callback URL using your app's scheme, so Google expects to redirect to that deep link—not to a localhost address.

To fix this, add your app's custom scheme redirect URI (for example, gogain-dev://auth/callback/google) to the list of authorized redirect URIs in the Google Cloud Console. Make sure your app.json defines the same scheme, and that your BetterAuth backend config includes all relevant schemes in trustedOrigins (like gogain-dev://, exp:// for Expo Go, etc.) docs expo client code discussion.

Once you update the Google Cloud Console with the correct scheme-based redirect URI, Google Sign-in should work in your Expo development environment.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other  Chat with Dosu Join Discord Share on X

<!-- gh-comment-id:3151175549 --> @dosubot[bot] commented on GitHub (Aug 4, 2025): <!-- Answer --> The root cause of the `redirect_uri_mismatch` error is that Expo apps using BetterAuth for Google OAuth require a custom scheme URI (like `gogain-dev://auth/callback/google`) as the redirect URI, not a web URL such as `https://localhost:8000/api/auth/callback/google`. The Expo client and BetterAuth construct the callback URL using your app's scheme, so Google expects to redirect to that deep link—not to a localhost address. To fix this, add your app's custom scheme redirect URI (for example, `gogain-dev://auth/callback/google`) to the list of authorized redirect URIs in the Google Cloud Console. Make sure your app.json defines the same scheme, and that your BetterAuth backend config includes all relevant schemes in `trustedOrigins` (like `gogain-dev://`, `exp://` for Expo Go, etc.) [docs](https://github.com/better-auth/better-auth/blob/987be984b4d840a409ca1e0d6098ee0f3303bcb6/docs/content/docs/integrations/expo.mdx) [expo client code](https://github.com/better-auth/better-auth/blob/987be984b4d840a409ca1e0d6098ee0f3303bcb6/packages/expo/src/client.ts) [discussion](https://github.com/better-auth/better-auth/issues/3711). Once you update the Google Cloud Console with the correct scheme-based redirect URI, Google Sign-in should work in your Expo development environment. <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/643ae4b8-a8f2-46a4-927a-c98d7926715c?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/643ae4b8-a8f2-46a4-927a-c98d7926715c?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/643ae4b8-a8f2-46a4-927a-c98d7926715c?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/643ae4b8-a8f2-46a4-927a-c98d7926715c?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/643ae4b8-a8f2-46a4-927a-c98d7926715c?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/643ae4b8-a8f2-46a4-927a-c98d7926715c?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/643ae4b8-a8f2-46a4-927a-c98d7926715c?feedback_type=other)</sup>&nbsp;&nbsp;[![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/better-auth/better-auth/issues/3781)
Author
Owner

@Zakisb commented on GitHub (Aug 4, 2025):

@dosu well i can't add gogain-dev://auth/callback/google since google requiresInvalid Redirect: must end with a public top-level domain (such as .com or .org).

<!-- gh-comment-id:3151709038 --> @Zakisb commented on GitHub (Aug 4, 2025): @dosu well i can't add gogain-dev://auth/callback/google since google requiresInvalid Redirect: must end with a public top-level domain (such as .com or .org).
Author
Owner

@dosubot[bot] commented on GitHub (Aug 4, 2025):

Right, Google doesn't allow custom URI schemes like gogain-dev:// as redirect URIs—they must end with a public domain (like .com or .org). This is a Google policy and can't be bypassed directly.

The standard approach for Expo/BetterAuth is to register your backend's web callback URL (e.g., http://localhost:8000/api/auth/callback/google) in the Google Cloud Console. When a user signs in, Google redirects to your backend, which completes the OAuth flow and then redirects to your app using a deep link (like gogain-dev://...)—this is handled automatically by BetterAuth's backend and Expo client integration. You do not need to register the deep link with Google; only the backend callback URL needs to be registered. The backend acts as a "proxy" between Google and your app, relaying the result via deep link after authentication is complete (docs, callback code).

If you still get a redirect_uri_mismatch, double-check that the redirect URI sent to Google exactly matches what you registered (including protocol, host, port, and path). For local dev, you can use a domain like lvh.me or a custom DNS entry pointing to your local IP if you want to avoid localhost (workaround discussion).

If you want to avoid the web-based OAuth flow entirely, you can use a native Google sign-in library (like @react-native-google-signin/google-signin), then send the resulting ID token to your backend for verification and session creation (example).

But for most Expo/BetterAuth setups, you only need to register the backend callback URL with Google, not the deep link. The backend will handle the rest.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other  Chat with Dosu Join Discord Share on X

<!-- gh-comment-id:3151732646 --> @dosubot[bot] commented on GitHub (Aug 4, 2025): <!-- Answer --> Right, Google doesn't allow custom URI schemes like gogain-dev:// as redirect URIs—they must end with a public domain (like .com or .org). This is a Google policy and can't be bypassed directly. The standard approach for Expo/BetterAuth is to register your backend's web callback URL (e.g., http://localhost:8000/api/auth/callback/google) in the Google Cloud Console. When a user signs in, Google redirects to your backend, which completes the OAuth flow and then redirects to your app using a deep link (like gogain-dev://...)—this is handled automatically by BetterAuth's backend and Expo client integration. You do not need to register the deep link with Google; only the backend callback URL needs to be registered. The backend acts as a "proxy" between Google and your app, relaying the result via deep link after authentication is complete ([docs](https://github.com/better-auth/better-auth/blob/987be984b4d840a409ca1e0d6098ee0f3303bcb6/docs/content/docs/integrations/expo.mdx), [callback code](https://github.com/better-auth/better-auth/blob/987be984b4d840a409ca1e0d6098ee0f3303bcb6/packages/better-auth/src/api/routes/callback.ts)). If you still get a redirect_uri_mismatch, double-check that the redirect URI sent to Google exactly matches what you registered (including protocol, host, port, and path). For local dev, you can use a domain like lvh.me or a custom DNS entry pointing to your local IP if you want to avoid localhost ([workaround discussion](https://github.com/better-auth/better-auth/issues/2444)). If you want to avoid the web-based OAuth flow entirely, you can use a native Google sign-in library (like @react-native-google-signin/google-signin), then send the resulting ID token to your backend for verification and session creation ([example](https://github.com/better-auth/better-auth/discussions/2125)). But for most Expo/BetterAuth setups, you only need to register the backend callback URL with Google, not the deep link. The backend will handle the rest. <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/26f58b67-69fe-4aa1-af0f-662ef669bef2?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/26f58b67-69fe-4aa1-af0f-662ef669bef2?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/26f58b67-69fe-4aa1-af0f-662ef669bef2?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/26f58b67-69fe-4aa1-af0f-662ef669bef2?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/26f58b67-69fe-4aa1-af0f-662ef669bef2?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/26f58b67-69fe-4aa1-af0f-662ef669bef2?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/26f58b67-69fe-4aa1-af0f-662ef669bef2?feedback_type=other)</sup>&nbsp;&nbsp;[![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/better-auth/better-auth/issues/3781)
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#27047