From c33fcd6fd8824ab4cb2f7e85f9fea02c9153ea9d Mon Sep 17 00:00:00 2001 From: Chiziaruhoma Ogbonda Date: Fri, 8 May 2026 15:25:48 +0100 Subject: [PATCH 1/3] docs: Update Google Sign-In setup and troubleshooting documentation with prerequisites and common mistakes --- .../04-providers/03-google/01-setup.md | 151 +++++++++++++----- .../03-google/04-troubleshooting.md | 16 +- 2 files changed, 116 insertions(+), 51 deletions(-) diff --git a/docs/06-concepts/11-authentication/04-providers/03-google/01-setup.md b/docs/06-concepts/11-authentication/04-providers/03-google/01-setup.md index 920f40c1..d7022fba 100644 --- a/docs/06-concepts/11-authentication/04-providers/03-google/01-setup.md +++ b/docs/06-concepts/11-authentication/04-providers/03-google/01-setup.md @@ -2,6 +2,14 @@ Sign in with Google requires a Google Cloud project. You also need platform-specific OAuth credentials depending on which platforms you target. +## Prerequisites + +Before following this guide, make sure you have: + +- A Google account with access to [Google Cloud Console](https://console.cloud.google.com/). +- A running Serverpod project (server, client, and Flutter app packages from `serverpod create`). +- The Serverpod auth module installed and configured per the [authentication setup](../../setup). If your project was generated with an older Serverpod version, follow that guide first to add `serverpod_auth_idp_server` and `serverpod_auth_idp_flutter` and to configure `pod.initializeAuthServices()` before continuing. + ## Get your Google credentials All platforms require a Web application OAuth client (used by the server). iOS and Android additionally require their own platform-specific OAuth clients. @@ -36,7 +44,7 @@ The People API is required for Serverpod to access basic user profile data durin 3. **Branding**: After completing the wizard, navigate to the [Branding](https://console.cloud.google.com/auth/branding) page from the sidebar. Fill in the remaining fields: app logo, app homepage link, privacy policy link, terms of service link, developer contact email, and **authorized domains**. These details appear on the OAuth consent screen shown to users during sign-in. - Add any domains you will use in production (e.g., `my-awesome-project.serverpod.space`) to **Authorized domains**. Google will reject redirect URIs that use domains not listed here. + Add the **root domain** you will deploy under (e.g., `serverpod.space`) to **Authorized domains**. Google stores only the top private domain, so a single root entry covers every subdomain you deploy under it. The root must be verified before Google accepts redirect URIs that use it. See [Verify your authorized domain](#1-verify-your-authorized-domain) for how to verify it. ![Branding configuration](/img/authentication/providers/google/10-branding.png) @@ -284,51 +292,106 @@ Web uses the same server OAuth client you created earlier, so you don't need a s ### Initialize the Google sign-in service -In your Flutter app's `main.dart` file (e.g., `my_project_flutter/lib/main.dart`), the template already sets up the `Client` and calls `client.auth.initialize()`. Add `client.auth.initializeGoogleSignIn()` right after it: +Open your Flutter app's `main.dart` (e.g., `my_project_flutter/lib/main.dart`). The Serverpod template already creates the `Client` and calls `client.auth.initialize()` inside `main()`. Add `client.auth.initializeGoogleSignIn()` on the line immediately after it. With the new line added, `main()` looks like this: ```dart -client.auth.initialize(); -client.auth.initializeGoogleSignIn(); +void main() async { + WidgetsFlutterBinding.ensureInitialized(); + + final serverUrl = await getServerUrl(); + + client = Client(serverUrl) + ..connectivityMonitor = FlutterConnectivityMonitor() + ..authSessionManager = FlutterAuthSessionManager(); + + client.auth.initialize(); + client.auth.initializeGoogleSignIn(); // add this line + + runApp(const MyApp()); +} ``` -### Add the sign-in widget +`initializeGoogleSignIn()` registers Google as an available identity provider on the client. Without it, the sign-in widget renders without a Google button and `GoogleSignInWidget` does nothing. -If you have configured the `SignInWidget` as described in the [setup section](../../setup#present-the-authentication-ui), the Google identity provider will be automatically detected and displayed in the sign-in widget. +### Show the Google sign-in button -You can also use the `GoogleSignInWidget` directly in your widget tree to include the Google authentication flow in your own custom UI: +The Serverpod template ships with a `SignInScreen` widget at `lib/screens/sign_in_screen.dart`. It listens to `client.auth.authInfoListenable` and swaps between `SignInWidget` while the user is signed out and the `child` you pass it once they sign in. `SignInWidget` auto-detects every initialized provider, so once `initializeGoogleSignIn()` has run the Google button appears inside it. ```dart +import 'package:flutter/material.dart'; import 'package:serverpod_auth_idp_flutter/serverpod_auth_idp_flutter.dart'; -GoogleSignInWidget( - client: client, - onAuthenticated: () { - // Do something when the user is authenticated. - // - // NOTE: You should not navigate to the home screen here, otherwise - // the user will have to sign in again every time they open the app. - }, - onError: (error) { - // Handle errors - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text('Error: $error')), - ); - }, -) +import '../main.dart'; + +class SignInScreen extends StatefulWidget { + final Widget child; + const SignInScreen({super.key, required this.child}); + + @override + State createState() => _SignInScreenState(); +} + +class _SignInScreenState extends State { + bool _isSignedIn = false; + + @override + void initState() { + super.initState(); + client.auth.authInfoListenable.addListener(_updateSignedInState); + _isSignedIn = client.auth.isAuthenticated; + } + + @override + void dispose() { + client.auth.authInfoListenable.removeListener(_updateSignedInState); + super.dispose(); + } + + void _updateSignedInState() { + setState(() { + _isSignedIn = client.auth.isAuthenticated; + }); + } + + @override + Widget build(BuildContext context) { + return _isSignedIn + ? widget.child + : Center( + child: SignInWidget( + client: client, + onError: (error) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text('Authentication failed: $error')), + ); + }, + ), + ); + } +} ``` -This renders a Google sign-in button like this: +:::warning +The `SignInScreen` listener is what swaps to your authenticated UI. If you also pass an `onAuthenticated` callback to `SignInWidget`, use it for transient feedback only (snackbars, analytics). Driving navigation from `onAuthenticated` instead of the listener sends the user back to sign-in on every app restart even though their session is still valid. +::: -![Google sign-in button](/img/authentication/providers/google/3-button.png) +In `main.dart`, the template wires this into `MyHomePage.build()`'s `Scaffold` behind a commented block. Comment out `body: const GreetingsScreen()` and uncomment the `SignInScreen(...)` block beneath it: -The widget automatically handles: +```dart +body: SignInScreen( + child: GreetingsScreen( + onSignOut: () async { + await client.auth.signOutDevice(); + }, + ), +), +``` -- Google Sign-In flow for iOS, Android, and Web. -- Lightweight sign-in (One Tap, FedCM) support. -- Token management. -- Underlying Google Sign-In package error handling. +`SignInWidget` renders the standard Google sign-in button: -For details on how to customize the Google Sign-In UI in your Flutter app, see the [customizing the UI section](./customizing-the-ui). +![Google sign-in button](/img/authentication/providers/google/3-button.png) + +To change the button's theme or build a fully custom UI, see [Customizing the UI](./customizing-the-ui). :::tip If you run into issues, see the [troubleshooting guide](./troubleshooting). @@ -338,16 +401,26 @@ If you run into issues, see the [troubleshooting guide](./troubleshooting). Before going live, complete the following steps: -### 1. Update the OAuth redirect URIs +### 1. Verify your authorized domain + +Google's **Authorized domains** field on the [Branding](https://console.cloud.google.com/auth/branding) page accepts only the **top private domain** (the root). Once the root is verified, every subdomain under it is automatically authorized, and you do not need to add each project subdomain separately. + +Verify ownership of your root domain (e.g., `example.com`) at [Google Search Console](https://search.google.com/search-console) by adding the DNS TXT record Google provides. After verification completes, add the root to **Authorized domains** in the Google Auth Platform. + +:::tip +A single verified root authorizes all of its subdomains. If Google rejects a domain you add, you are likely entering a full subdomain instead of the root. +::: + +### 2. Update the OAuth redirect URIs Go back to the [server OAuth client](#create-the-server-oauth-client-web-application) in the Google Auth Platform and add your production server's public URL to both **Authorized JavaScript origins** and **Authorized redirect URIs**: -- **Authorized JavaScript origins**: `https://your-domain.serverpod.space` -- **Authorized redirect URIs**: `https://your-domain.serverpod.space` +- **Authorized JavaScript origins**: `https://my-awesome-project.serverpod.space` +- **Authorized redirect URIs**: `https://my-awesome-project.serverpod.space` Replace the URL with your actual production web server address. -### 2. Store the production credentials +### 3. Store the production credentials Add the `googleClientSecret` entry to the `production:` section of `config/passwords.yaml`, using the production redirect URI: @@ -359,7 +432,7 @@ production: "web": { "client_id": "your-client-id.apps.googleusercontent.com", "client_secret": "your-client-secret", - "redirect_uris": ["https://your-domain.serverpod.space"] + "redirect_uris": ["https://my-awesome-project.serverpod.space"] } } ``` @@ -369,12 +442,12 @@ Alternatively, set the `SERVERPOD_PASSWORD_googleClientSecret` [environment vari If you're deploying to Serverpod Cloud, set the password with the `scloud` CLI instead. Save the JSON to a file and run: ```bash -scloud password set googleClientSecret --from-file path/to/google-client-secret.json +scloud password set googleClientSecret --project my-awesome-project --from-file path/to/google-client-secret.json ``` -See the [Serverpod Cloud passwords guide](https://docs.serverpod.dev/cloud/guides/passwords) for more details. +Replace `my-awesome-project` with your Cloud project ID. You can omit `--project` if you have already linked the project locally with `scloud project link`. See the [Serverpod Cloud passwords guide](https://docs.serverpod.dev/cloud/guides/passwords) for more details. -### 3. Update the Android OAuth client with the release SHA-1 (Android only) +### 4. Update the Android OAuth client with the release SHA-1 (Android only) The Android OAuth client you created during setup uses your debug SHA-1 fingerprint. Release builds are signed with a different key, so you need to add the release SHA-1 as well. @@ -392,7 +465,7 @@ Once you have the SHA-1, go back to your Android OAuth client in the Google Auth Forgetting this step is one of the most common reasons Google Sign-In works in debug builds but silently fails after publishing to the Play Store. ::: -### 4. Publish the OAuth consent screen +### 5. Publish the OAuth consent screen While the app is in **Testing** mode, only the test users you added on the [Audience](https://console.cloud.google.com/auth/audience) page, in the Google Auth Platform, can sign in. All other users will see an error. diff --git a/docs/06-concepts/11-authentication/04-providers/03-google/04-troubleshooting.md b/docs/06-concepts/11-authentication/04-providers/03-google/04-troubleshooting.md index 339aec05..ce40b50c 100644 --- a/docs/06-concepts/11-authentication/04-providers/03-google/04-troubleshooting.md +++ b/docs/06-concepts/11-authentication/04-providers/03-google/04-troubleshooting.md @@ -11,7 +11,7 @@ Go through this before investigating a specific error. Most problems come from a - [ ] Create a **Google Cloud project** in the [Google Cloud Console](https://console.cloud.google.com/). - [ ] Enable the **People API** in your project. - [ ] In **Google Auth Platform**, complete the initial setup (wizard) and add the required scopes on **Data Access** (`.../auth/userinfo.email` and `.../auth/userinfo.profile`). -- [ ] On **Branding** ([Branding](https://console.cloud.google.com/auth/branding)), complete the OAuth consent screen (logo, homepage, privacy policy, terms of service, and developer contact) and add every hostname you will use under **Authorized domains** (redirect URIs must use a listed domain). +- [ ] On **Branding** ([Branding](https://console.cloud.google.com/auth/branding)), complete the OAuth consent screen (logo, homepage, privacy policy, terms of service, and developer contact) and add the **root domain** (top private domain) under **Authorized domains**. Google stores only the root, so a single verified entry covers all of its subdomains. See [Verify your authorized domain](./setup#1-verify-your-authorized-domain). - [ ] Add **test users** on **Audience** while in **Testing** mode ([Audience](https://console.cloud.google.com/auth/audience)), or **Publish app** when everyone should be able to sign in. - [ ] Create a **Web application** OAuth client with **Authorized JavaScript origins** and **Authorized redirect URIs** set to your Serverpod **web server** (`http://localhost:8082` locally, not port `8080`). Copy the **Client ID** and **Client secret**. - [ ] Add `googleClientSecret` to `config/passwords.yaml` with your client ID, client secret, and matching `redirect_uris`. For production, use the live web server URL in Google Cloud and in `production:` (or env vars) as in [Publishing to production](./setup#publishing-to-production). @@ -42,9 +42,9 @@ Go through this before investigating a specific error. Most problems come from a Common mistakes: -* Using port `8080` (the API server) instead of `8082` (the web server). Check `config/development.yaml` under `webServer` for the correct port. -* Adding a trailing slash (e.g., `http://localhost:8082/` instead of `http://localhost:8082`). -* For Web apps: not adding the Flutter web app's origin (e.g., `http://localhost:49660`) to **Authorized JavaScript origins**. This is separate from the Serverpod web server address. See the [Web setup section](./setup#web) for details. +- Using port `8080` (the API server) instead of `8082` (the web server). Check `config/development.yaml` under `webServer` for the correct port. +- Adding a trailing slash (e.g., `http://localhost:8082/` instead of `http://localhost:8082`). +- For Web apps: not adding the Flutter web app's origin (e.g., `http://localhost:49660`) to **Authorized JavaScript origins**. This is separate from the Serverpod web server address. See the [Web setup section](./setup#web) for details. ## Sign-in works for you but not for other users @@ -54,14 +54,6 @@ Common mistakes: **Resolution:** Navigate to the [Audience](https://console.cloud.google.com/auth/audience) page and click **Publish App** to allow any Google account to sign in. If your app uses sensitive or restricted scopes, Google may require a verification review before publishing. -## Production redirect URIs rejected by Google - -**Problem:** When adding your production domain to Authorized redirect URIs, Google rejects it with an error about unauthorized domains. - -**Cause:** Your production domain is not listed under **Authorized domains** on the Branding page. - -**Resolution:** Navigate to the [Branding](https://console.cloud.google.com/auth/branding) page and add your production domain (e.g., `my-awesome-project.serverpod.space`) to **Authorized domains**. Google requires redirect URIs to use domains listed here. - ## Flutter web sign-in fails with origin mismatch **Problem:** Google Sign-In on Flutter web fails with an origin mismatch error, even though you added `http://localhost:8082` to the OAuth client. From d991a8cdc4b0270f03f835bad7d75885c2f0fd5d Mon Sep 17 00:00:00 2001 From: Chiziaruhoma Ogbonda Date: Mon, 11 May 2026 13:35:48 +0100 Subject: [PATCH 2/3] docs: Enhance Google Sign-In setup documentation with clearer instructions for authorized domains and production credentials --- .../04-providers/03-google/01-setup.md | 36 +++++++++++++------ 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/docs/06-concepts/11-authentication/04-providers/03-google/01-setup.md b/docs/06-concepts/11-authentication/04-providers/03-google/01-setup.md index d7022fba..2d8dc7ae 100644 --- a/docs/06-concepts/11-authentication/04-providers/03-google/01-setup.md +++ b/docs/06-concepts/11-authentication/04-providers/03-google/01-setup.md @@ -44,7 +44,9 @@ The People API is required for Serverpod to access basic user profile data durin 3. **Branding**: After completing the wizard, navigate to the [Branding](https://console.cloud.google.com/auth/branding) page from the sidebar. Fill in the remaining fields: app logo, app homepage link, privacy policy link, terms of service link, developer contact email, and **authorized domains**. These details appear on the OAuth consent screen shown to users during sign-in. - Add the **root domain** you will deploy under (e.g., `serverpod.space`) to **Authorized domains**. Google stores only the top private domain, so a single root entry covers every subdomain you deploy under it. The root must be verified before Google accepts redirect URIs that use it. See [Verify your authorized domain](#1-verify-your-authorized-domain) for how to verify it. + Add the **root domain** you will deploy under to **Authorized domains**. Google stores only the top private domain, so a single root entry covers every subdomain you deploy under it. + + If you deploy on Serverpod Cloud, add `serverpod.space`. It is already verified by Serverpod, so you only need to add it here, no DNS verification is required on your end. For custom domains, see [Verify your authorized domain](#1-verify-your-authorized-domain). ![Branding configuration](/img/authentication/providers/google/10-branding.png) @@ -61,7 +63,7 @@ The People API is required for Serverpod to access basic user profile data durin ![Audience and test users](/img/authentication/providers/google/7-audience.png) :::tip - Leave the app in **Testing** mode for now. You can [publish it](#publishing-to-production) after verifying that sign-in works end to end. + Leave the app in **Testing** mode for now. You can [publish it](#5-publish-the-oauth-consent-screen) after verifying that sign-in works end to end. ::: ### Create the server OAuth client (Web application) @@ -405,7 +407,9 @@ Before going live, complete the following steps: Google's **Authorized domains** field on the [Branding](https://console.cloud.google.com/auth/branding) page accepts only the **top private domain** (the root). Once the root is verified, every subdomain under it is automatically authorized, and you do not need to add each project subdomain separately. -Verify ownership of your root domain (e.g., `example.com`) at [Google Search Console](https://search.google.com/search-console) by adding the DNS TXT record Google provides. After verification completes, add the root to **Authorized domains** in the Google Auth Platform. +If you deploy on Serverpod Cloud under a `*.serverpod.space` subdomain, `serverpod.space` is already verified by Serverpod. Just add `serverpod.space` to **Authorized domains** in the Google Auth Platform, no DNS verification is required on your end. + +For a custom domain, verify ownership of your root domain (e.g., `example.com`) at [Google Search Console](https://search.google.com/search-console) by adding the DNS TXT record Google provides. After verification completes, add the root to **Authorized domains** in the Google Auth Platform. :::tip A single verified root authorizes all of its subdomains. If Google rejects a domain you add, you are likely entering a full subdomain instead of the root. @@ -418,11 +422,19 @@ Go back to the [server OAuth client](#create-the-server-oauth-client-web-applica - **Authorized JavaScript origins**: `https://my-awesome-project.serverpod.space` - **Authorized redirect URIs**: `https://my-awesome-project.serverpod.space` -Replace the URL with your actual production web server address. +Replace the URL with your actual production web server address. On Serverpod Cloud, your project is served from `https://.serverpod.space`. + +### 3. Set production credentials + +Production runs out of the `production:` section of `passwords.yaml`, which is separate from the `development:` section you populated during setup. Adding production credentials does not replace your development ones, both stay in place and Serverpod picks the right set based on the run mode. -### 3. Store the production credentials +The production `googleClientSecret` reuses the same web client ID and secret from setup, but lists your production redirect URI rather than the development one. If you use a different OAuth client for production, [create another web client](#create-the-server-oauth-client-web-application) first and use its values below. -Add the `googleClientSecret` entry to the `production:` section of `config/passwords.yaml`, using the production redirect URI: +Pick the path that matches your deployment: + +#### Self-hosted + +Add `googleClientSecret` to the `production:` section of `passwords.yaml` with the production redirect URI: ```yaml production: @@ -439,15 +451,17 @@ production: Alternatively, set the `SERVERPOD_PASSWORD_googleClientSecret` [environment variable](../../../07-configuration.md#2-via-environment-variables) on your production server with the same JSON value. -If you're deploying to Serverpod Cloud, set the password with the `scloud` CLI instead. Save the JSON to a file and run: +#### Serverpod Cloud + +Use `https://.serverpod.space` as the redirect URI in the JSON. Save it to a file and use `scloud password set` with `--from-file`: ```bash -scloud password set googleClientSecret --project my-awesome-project --from-file path/to/google-client-secret.json +scloud password set googleClientSecret --from-file path/to/google-client-secret.json ``` -Replace `my-awesome-project` with your Cloud project ID. You can omit `--project` if you have already linked the project locally with `scloud project link`. See the [Serverpod Cloud passwords guide](https://docs.serverpod.dev/cloud/guides/passwords) for more details. +Run this from your linked server project directory, or pass `--project ` on the call. See the [Serverpod Cloud passwords guide](https://docs.serverpod.dev/cloud/guides/passwords) for project linking and other options. -### 4. Update the Android OAuth client with the release SHA-1 (Android only) +### 4. Update the Android OAuth client with the release SHA-1 The Android OAuth client you created during setup uses your debug SHA-1 fingerprint. Release builds are signed with a different key, so you need to add the release SHA-1 as well. @@ -467,6 +481,6 @@ Forgetting this step is one of the most common reasons Google Sign-In works in d ### 5. Publish the OAuth consent screen -While the app is in **Testing** mode, only the test users you added on the [Audience](https://console.cloud.google.com/auth/audience) page, in the Google Auth Platform, can sign in. All other users will see an error. +While the app is in **Testing** mode, only the test users you added on the [Audience](https://console.cloud.google.com/auth/audience) page, in the Google Auth Platform, can sign in. All other users will see an error. Navigate to the **Audience** page and click **Publish App** to allow any Google account to sign in. If your app uses sensitive or restricted scopes, Google may require a verification review before publishing. From f84cd5751b581e845aef534fe7fc19bf9e2112a4 Mon Sep 17 00:00:00 2001 From: Chiziaruhoma Ogbonda Date: Mon, 11 May 2026 13:53:44 +0100 Subject: [PATCH 3/3] docs: Clarify Google Sign-In initialization and troubleshooting steps, including details on authorized domains and production redirect URI verification --- .../04-providers/03-google/01-setup.md | 4 ++-- .../04-providers/03-google/04-troubleshooting.md | 10 +++++++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/docs/06-concepts/11-authentication/04-providers/03-google/01-setup.md b/docs/06-concepts/11-authentication/04-providers/03-google/01-setup.md index 2d8dc7ae..3fc3f784 100644 --- a/docs/06-concepts/11-authentication/04-providers/03-google/01-setup.md +++ b/docs/06-concepts/11-authentication/04-providers/03-google/01-setup.md @@ -313,11 +313,11 @@ void main() async { } ``` -`initializeGoogleSignIn()` registers Google as an available identity provider on the client. Without it, the sign-in widget renders without a Google button and `GoogleSignInWidget` does nothing. +`initializeGoogleSignIn()` initializes the underlying `google_sign_in` SDK (loading the client IDs you configured) and registers a sign-out hook so signing out of Serverpod also signs the user out of their Google session. `SignInWidget` can lazily initialize Google on first use, but calling this at startup wires the sign-out hook early and avoids a delay on the first tap. ### Show the Google sign-in button -The Serverpod template ships with a `SignInScreen` widget at `lib/screens/sign_in_screen.dart`. It listens to `client.auth.authInfoListenable` and swaps between `SignInWidget` while the user is signed out and the `child` you pass it once they sign in. `SignInWidget` auto-detects every initialized provider, so once `initializeGoogleSignIn()` has run the Google button appears inside it. +The Serverpod template ships with a `SignInScreen` widget at `lib/screens/sign_in_screen.dart`. It listens to `client.auth.authInfoListenable` and swaps between `SignInWidget` while the user is signed out and the `child` you pass it once they sign in. `SignInWidget` auto-detects which identity provider endpoints are registered on the server, so once `GoogleIdpEndpoint` is exposed and `serverpod generate` has run, the Google button appears inside it. ```dart import 'package:flutter/material.dart'; diff --git a/docs/06-concepts/11-authentication/04-providers/03-google/04-troubleshooting.md b/docs/06-concepts/11-authentication/04-providers/03-google/04-troubleshooting.md index ce40b50c..4d8b68bb 100644 --- a/docs/06-concepts/11-authentication/04-providers/03-google/04-troubleshooting.md +++ b/docs/06-concepts/11-authentication/04-providers/03-google/04-troubleshooting.md @@ -11,7 +11,7 @@ Go through this before investigating a specific error. Most problems come from a - [ ] Create a **Google Cloud project** in the [Google Cloud Console](https://console.cloud.google.com/). - [ ] Enable the **People API** in your project. - [ ] In **Google Auth Platform**, complete the initial setup (wizard) and add the required scopes on **Data Access** (`.../auth/userinfo.email` and `.../auth/userinfo.profile`). -- [ ] On **Branding** ([Branding](https://console.cloud.google.com/auth/branding)), complete the OAuth consent screen (logo, homepage, privacy policy, terms of service, and developer contact) and add the **root domain** (top private domain) under **Authorized domains**. Google stores only the root, so a single verified entry covers all of its subdomains. See [Verify your authorized domain](./setup#1-verify-your-authorized-domain). +- [ ] On **Branding** ([Branding](https://console.cloud.google.com/auth/branding)), complete the OAuth consent screen (logo, homepage, privacy policy, terms of service, and developer contact) and add the **root domain** (top private domain) under **Authorized domains**. Google stores only the root, so a single verified entry covers all of its subdomains. On Serverpod Cloud, add `serverpod.space` (already verified by Serverpod, no DNS setup needed). For custom domains, see [Verify your authorized domain](./setup#1-verify-your-authorized-domain). - [ ] Add **test users** on **Audience** while in **Testing** mode ([Audience](https://console.cloud.google.com/auth/audience)), or **Publish app** when everyone should be able to sign in. - [ ] Create a **Web application** OAuth client with **Authorized JavaScript origins** and **Authorized redirect URIs** set to your Serverpod **web server** (`http://localhost:8082` locally, not port `8080`). Copy the **Client ID** and **Client secret**. - [ ] Add `googleClientSecret` to `config/passwords.yaml` with your client ID, client secret, and matching `redirect_uris`. For production, use the live web server URL in Google Cloud and in `production:` (or env vars) as in [Publishing to production](./setup#publishing-to-production). @@ -46,6 +46,14 @@ Common mistakes: - Adding a trailing slash (e.g., `http://localhost:8082/` instead of `http://localhost:8082`). - For Web apps: not adding the Flutter web app's origin (e.g., `http://localhost:49660`) to **Authorized JavaScript origins**. This is separate from the Serverpod web server address. See the [Web setup section](./setup#web) for details. +## Production redirect URIs rejected by Google + +**Problem:** When adding your production domain to **Authorized redirect URIs** on the Web OAuth client, Google rejects it with an error about unauthorized domains. + +**Cause:** The redirect URI's root domain (the top private domain) has not been verified and added to **Authorized domains** on the Branding page. Google requires the root to be a verified Authorized Domain before it accepts redirect URIs that use it. + +**Resolution:** Add the root domain (e.g., `serverpod.space` or your custom root) to **Authorized domains**, then retry the redirect URI. On Serverpod Cloud, the `serverpod.space` root is already verified, so you only need to add `serverpod.space` to **Authorized domains**. For a custom domain, verify ownership at [Google Search Console](https://search.google.com/search-console) first. See [Verify your authorized domain](./setup#1-verify-your-authorized-domain). + ## Sign-in works for you but not for other users **Problem:** Sign-in works for your Google account but other users get an error screen from Google saying the app is not verified or access is denied.