Flootdocs
AuthSocial

Google

Configure Google Sign-In for your Floot app on every supported platform.

The Google button is already on the sign-in and sign-up screens, next to email and password. What is missing is a Google Cloud project to point it at, and one flag.

Behind that single button are two different flows, chosen by platform rather than by configuration:

PlatformFlowHow it works
Android, iOSNativeThe google_sign_in plugin returns an identity token, which goes to Supabase directly
Web, macOS, Windows, LinuxBrowserSupabase Auth's /authorize endpoint opens in a browser, and a deep link brings the user back

Every example below uses the project from floot create my_app --org com.acme. Substitute your own.

Turn Google Sign-In on

Requires ENABLE_GOOGLE_SIGN_IN

Google Sign-In is off in a new project. Set `ENABLE_GOOGLE_SIGN_IN=true` in `.env.local` to use this section.

.env.local
ENABLE_GOOGLE_SIGN_IN=true

The flag decides whether the google_sign_in plugin is registered at all, so it is the native flow (Android and iOS) that stops dead without it: the button is still there, and tapping it fails with the generic "unexpected error" toast. The browser flow never touches the plugin, which is why Google sign-in can appear to work on macOS or Windows while doing nothing on a phone.

Both client ids, on every platform

This is the single most common way to get Google Sign-In half-working. When the flag is on, the app requires both OAUTH_GOOGLE_IOS_CLIENT_ID and OAUTH_GOOGLE_WEB_CLIENT_ID, on Android and on desktop too, not only on iOS.

A release build will not tell you

Dart strips its own asserts from release builds, and this check is one of them. Ship with one of the two variables empty and nothing crashes; sign-in just quietly never completes. Create both credentials in the console before you enable the flag.

Google Cloud Platform Setup

Create a new project

Google Cloud Console → Cloud overview (sidebar) → Dashboard → Create project

Create credentials

APIs & Services (sidebar) → Credentials → Create credentials → OAuth client ID

  • Application type > iOS
  • Name > give a meaningful name
  • Bundle ID > floot create already set it. For my_app --org com.acme it is com.acme.myApp, the project name camel-cased, which is also what OAUTH_APPLE_CLIENT_ID uses. To read it out of the project instead:
    • Open the ios folder of your Flutter project in Xcode (right click on the folder → Open in Xcode)
    • Runner (sidebar) → General (tab bar) → Runner (TARGETS sidebar) → Identity → Bundle Identifier
  • App Store ID and Team ID > only if the app is already published on the Apple App Store

→ Create

iOS needs a Web client id as well. Head to the Web tab once you are done here.

Locally, [auth.external.google].skip_nonce_check already ships true. On Supabase Cloud you have to enable Skip nonce check yourself, in the Google provider on the Supabase Dashboard. Self-hosted, set GOTRUE_EXTERNAL_GOOGLE_SKIP_NONCE_CHECK to "true" on the auth service. See In production.

This information is shown to the user when giving consent to your app. In particular, make sure you have set up links to your app's privacy policy and terms of service.

APIs & Services (sidebar) → OAuth consent screen → Fill needed infos

Floot App Setup

Which env file

.env.local and supabase/.env.local are the local-development files. Release builds read .env instead, which floot create does not write; see Building for release.

CFBundleURLTypes

iOS needs your Google iOS client id as a URL scheme, in reverse-DNS form: Apple's convention for URL types.

Copy your iOS Client ID from Google Cloud Console, which looks like this:

861823949799-vc35cprkp249096uujjn0vvnmcvjppkn.apps.googleusercontent.com

Remove the domain part: get rid of .apps.googleusercontent.com

861823949799-vc35cprkp249096uujjn0vvnmcvjppkn

Add the domain part back at the beginning, in reverse order:

com.googleusercontent.apps.861823949799-vc35cprkp249096uujjn0vvnmcvjppkn

Put it in ios/Runner/Info.plist, replacing the your_google_ios_REVERSED_client_id placeholder. It is the first of the two schemes there; the second is your deep-link scheme and must stay as it is.

ios/Runner/Info.plist
<key>CFBundleURLTypes</key>
<array>
  <dict>
    <key>CFBundleTypeRole</key>
    <string>Editor</string>
    <key>CFBundleURLSchemes</key>
    <array>
      <string>com.googleusercontent.apps.861823949799-vc35cprkp249096uujjn0vvnmcvjppkn</string>
      <string>com.acme.myapp</string>
    </array>
  </dict>
</array>

The app's environment

.env.local
ENABLE_GOOGLE_SIGN_IN=true
OAUTH_GOOGLE_IOS_CLIENT_ID=861823949799-vc35cprkp249096uujjn0vvnmcvjppkn.apps.googleusercontent.com
OAUTH_GOOGLE_WEB_CLIENT_ID=861823949799-8p0vgc9ne7ok4h5r2j1qafd6b3ltmuo1.apps.googleusercontent.com

The iOS client id goes in unreversed here. Only Info.plist wants the reversed form.

The Supabase environment and config

Supabase authenticates as the Web client, not the iOS one, so the values it needs are the same on every platform.

supabase/.env.local
OAUTH_GOOGLE_WEB_CLIENT_ID=861823949799-8p0vgc9ne7ok4h5r2j1qafd6b3ltmuo1.apps.googleusercontent.com
OAUTH_GOOGLE_WEB_SECRET=GOCSPX-...
SB_AUTH_EXTERNAL_REDIRECT_URI=http://127.0.0.1:54321/auth/v1/callback
supabase/config.toml
[auth.external.google]
enabled = true

Everything else in that block is already wired to a variable: client_id to OAUTH_GOOGLE_WEB_CLIENT_ID, secret to OAUTH_GOOGLE_WEB_SECRET, redirect_uri to SB_AUTH_EXTERNAL_REDIRECT_URI. Fill the variables, leave the env(...) references alone.

Head to the Web tab and create the Web client if you have not already.

No deep link is involved on iOS: the sign-in sheet is native, so there is no browser to come back from.

In production

Your deployed backend needs its own Google provider, authenticating as the Web client:

  • The Web client lists your backend's callback among its Authorized redirect URIs (Create credentials), next to any development one.
  • Supabase Cloud: turn Google on under Authentication → Sign In / Providers → Google in the dashboard, enter the Web client's ID and secret, and enable Skip nonce check. See Providers.
  • Self-hosted: set GOTRUE_EXTERNAL_GOOGLE_ENABLED: "true", GOTRUE_EXTERNAL_GOOGLE_CLIENT_ID, GOTRUE_EXTERNAL_GOOGLE_SECRET, GOTRUE_EXTERNAL_GOOGLE_REDIRECT_URI (https://api.myapp.com/auth/v1/callback) and GOTRUE_EXTERNAL_GOOGLE_SKIP_NONCE_CHECK: "true" on the auth service in your own compose file; the stock file carries the first four commented out. Then recreate the auth container. See Auth defaults that differ.

The functions' SB_AUTH_EXTERNAL_REDIRECT_URI holds the same callback on the deployed backend; it is in the function secrets on Supabase Cloud and self-hosted. The app's half, ENABLE_GOOGLE_SIGN_IN and both client ids, goes into the release .env (see The release .env), and Android needs the SHA-1 of the key that signs store builds (see Android: replace the debug signing).

supabase config push could send [auth.external.google] from config.toml to a linked Cloud project instead, but it fills each env() from your local supabase/.env.local, so it would push the 127.0.0.1 callback. Set the provider in the dashboard, or read Alternative: settings from config.toml first.

On this page