Setup
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.
- A running Serverpod project (server, client, and Flutter app packages from
serverpod create). - The Serverpod auth module installed and configured per the authentication setup. If your project was generated with an older Serverpod version, follow that guide first to add
serverpod_auth_idp_serverandserverpod_auth_idp_flutterand to configurepod.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.
Create a Google Cloud project
-
Go to Create a project.
-
Enter a Project name (e.g.
My Serverpod App) and click Create. -
Create a new project (or select an existing one).
Enable People API
The People API is required for Serverpod to access basic user profile data during sign-in.
-
Navigate to the People API page in your project.
-
Click Enable.

Configure Google Auth Platform
-
Navigate to the Google Auth Platform overview and click Get started if you haven't enabled it yet.

-
Project configuration: Complete the setup wizard by filling in the required fields across each step (App Information, Audience, Contact Information) and click Create.

-
Branding: After completing the wizard, navigate to the 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 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.
-
Data access: Navigate to the Data Access page and add the required scopes:
.../auth/userinfo.emailand.../auth/userinfo.profile.
tipIf you need access to additional Google APIs (e.g., Calendar, Drive), you can add more scopes here. See Accessing Google APIs for details on requesting additional scopes and using them with the
getExtraGoogleInfoCallbackon the server. -
Audience: Navigate to the Audience page. While in development, the app is in Testing mode, which means only users you explicitly add as test users can sign in (up to 100). Add your email as a test user so you can test the integration.
tipLeave the app in Testing mode for now. You can publish it after verifying that sign-in works end to end.
Create the server OAuth client (Web application)
All platforms (iOS, Android, and Web) require a Web application OAuth client for the server. This is the only client type that provides a client secret, which Serverpod needs to verify sign-in tokens on the server side.
-
In the Google Auth Platform, navigate to Clients and click Create Client.
-
Select Web application as the application type.
-
Add the following URIs:
- Authorized JavaScript origins: The origin that is allowed to make requests to Google's OAuth servers. For Serverpod, this is your web server address.
- Authorized redirect URIs: The URL Google redirects the user back to after they sign in. Serverpod handles this callback on the web server as well.
Serverpod runs three servers locally (see
config/development.yaml): the API server on port 8080, the Insights server on 8081, and the web server on port 8082. The Google OAuth flow uses the web server, so both fields should point to port 8082:Environment Authorized JavaScript origins Authorized redirect URIs Local development http://localhost:8082http://localhost:8082Production Your web server's public URL (e.g., https://my-awesome-project.serverpod.space)Your web server's public URL You can find these ports in your server's
config/development.yamlunderwebServer.
-
Click Create.
-
Copy the Client ID and Client secret shown on screen. You will need both in the next step.
Store your credentials
Your server's config/passwords.yaml already has development:, staging:, and production: sections from the project template. Add the googleClientSecret key to the development: section using the client ID and client secret you just copied:
development:
# ... existing keys (database, redis, serviceSecret, etc.) ...
googleClientSecret: |
{
"web": {
"client_id": "your-client-id.apps.googleusercontent.com",
"client_secret": "your-client-secret",
"redirect_uris": ["http://localhost:8082"]
}
}
Replace your-client-id and your-client-secret with the values from the Google Auth Platform. The redirect_uris must match the Authorized redirect URIs you configured in the previous step.
For production, add the same googleClientSecret entry to the production: section of passwords.yaml (with your production redirect URI), or set the SERVERPOD_PASSWORD_googleClientSecret environment variable on your production server.
Never commit config/passwords.yaml to version control. It contains your OAuth client secret. Use environment variables or a secrets manager in production.
Carefully maintain correct indentation for YAML block scalars. The googleClientSecret block uses a |; any indentation error will silently break the JSON, resulting in authentication failures.
Server-side configuration
Add the Google identity provider
Your server's server.dart file (e.g., my_project_server/lib/server.dart) should already contain a pod.initializeAuthServices() call if your project was created with the Serverpod project template (serverpod create). If it's not there, see Setup first to configure the auth module and JWT settings.
Add the Google import and GoogleIdpConfigFromPasswords() to the existing identityProviderBuilders list:
import 'package:serverpod_auth_idp_server/providers/google.dart';
pod.initializeAuthServices(
tokenManagerBuilders: [
JwtConfigFromPasswords(),
],
identityProviderBuilders: [
// ... any existing providers (e.g., EmailIdpConfigFromPasswords) ...
GoogleIdpConfigFromPasswords(),
],
);
GoogleIdpConfigFromPasswords() automatically loads the client secret from the googleClientSecret key in config/passwords.yaml (or the SERVERPOD_PASSWORD_googleClientSecret environment variable).
If you need more control over how the client secret is loaded, you can use GoogleIdpConfig(clientSecret: GoogleClientSecret.fromJsonString(...)) instead. See the customizations page for details.
Create the endpoint
Create a new endpoint file in your server project (e.g., my_project_server/lib/src/auth/google_idp_endpoint.dart) alongside the existing auth endpoints. Extending the base class registers the sign-in methods with your server so the Flutter client can call them to complete the authentication flow:
import 'package:serverpod_auth_idp_server/providers/google.dart';
class GoogleIdpEndpoint extends GoogleIdpBaseEndpoint {}
Generate code and apply migrations
Run the following commands from your server project directory (e.g., my_project_server/) to generate client code and apply the database migration:
serverpod generate
serverpod create-migration
dart run bin/main.dart --apply-migrations
Skipping the migration will cause the server to crash at runtime when the Google provider tries to read or write user data. More detailed instructions can be found in the general identity providers setup section.
Client-side configuration
The Android and iOS integrations use the google_sign_in package under the hood, so any documentation there should also apply to this setup.
iOS
-
In the Google Auth Platform, navigate to Clients and click Create Client.
-
Select iOS as the application type.
-
Fill in your app's Bundle ID and any other required information.
-
Click Create and download the
.plistfile.
-
Open the
Info.plistfile in your Flutter project (e.g.,my_project_flutter/ios/Runner/Info.plist) and add the following keys inside the top-level<dict>:<dict>...<key>GIDClientID</key><string>your_ios_client_id</string><key>GIDServerClientID</key><string>your_server_client_id</string></dict>Replace
your_ios_client_idwith theCLIENT_IDvalue from the downloaded plist file, andyour_server_client_idwith the client ID from the Web application OAuth client you created earlier.
Add the URL scheme
To allow navigation back to the app after sign-in, add the URL scheme to the same Info.plist file. The scheme is the reversed client ID of your iOS app (found as REVERSED_CLIENT_ID in the downloaded plist file). Add the following inside the top-level <dict>:
<dict>
...
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLSchemes</key>
<array>
<string>com.googleusercontent.apps.your_client_id</string>
</array>
</dict>
</array>
</dict>
Replace the URL scheme with your actual reversed client ID.
Without the URL scheme, the OAuth callback never returns to your app and sign-in silently hangs.
Android
-
In the Google Auth Platform, navigate to Clients and click Create Client.
-
Select Android as the application type.
-
Fill in your app's Package name and SHA-1 certificate fingerprint. You can get the debug SHA-1 hash by running this from your Flutter project's
android/directory (e.g.,my_project_flutter/android/):./gradlew signingReport -
Click Create and download the JSON file.

-
Place the file inside your Flutter project's
android/app/directory (e.g.,my_project_flutter/android/app/) and rename it togoogle-services.json.
The downloaded google-services.json may not include a web OAuth client entry, which is required for Google Sign-In to resolve the server client ID. If sign-in fails, provide the client IDs programmatically as described on the customizations page.
Web
Web uses the same server OAuth client you created earlier, so you don't need a separate client. However, for web, the sign-in request originates from the Flutter app running in the browser, not from the Serverpod web server. Google requires this origin to be listed as well.
-
Choose a fixed port for your Flutter web app. Google OAuth requires exact origin matches, and Flutter picks a random port on each run by default. To keep things consistent, run Flutter on a fixed port using
--web-port:flutter run -d chrome --web-hostname localhost --web-port=49660-d chrome: Run on the Chrome browser.--web-hostname localhost: Bind to localhost.--web-port=49660: Use a fixed port (pick any available port). This is the value you will add to Authorized JavaScript origins in the next step.
-
Update the server OAuth client. Go back to the server OAuth client you created in the previous section and add your Flutter web app's origin to Authorized JavaScript origins:
- For local development:
http://localhost:49660(or whichever port you chose) - For production: your Flutter web app's domain (e.g.,
https://my-awesome-project.serverpod.space)
The Authorized redirect URIs should already contain your Serverpod web server's address (
http://localhost:8082) from the earlier setup. You don't need to change it.
- For local development:
-
Add the client ID to your Flutter project's
web/index.html(e.g.,my_project_flutter/web/index.html). In the<head>section, add:<head>...<meta name="google-signin-client_id" content="your_server_client_id"></head>Replace
your_server_client_idwith the client ID from your Web application OAuth client.
Present the authentication UI
Initialize the Google sign-in service
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:
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());
}
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 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.
import 'package:flutter/material.dart';
import 'package:serverpod_auth_idp_flutter/serverpod_auth_idp_flutter.dart';
import '../main.dart';
class SignInScreen extends StatefulWidget {
final Widget child;
const SignInScreen({super.key, required this.child});
State<SignInScreen> createState() => _SignInScreenState();
}
class _SignInScreenState extends State<SignInScreen> {
bool _isSignedIn = false;
void initState() {
super.initState();
client.auth.authInfoListenable.addListener(_updateSignedInState);
_isSignedIn = client.auth.isAuthenticated;
}
void dispose() {
client.auth.authInfoListenable.removeListener(_updateSignedInState);
super.dispose();
}
void _updateSignedInState() {
setState(() {
_isSignedIn = client.auth.isAuthenticated;
});
}
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')),
);
},
),
);
}
}
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.
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:
body: SignInScreen(
child: GreetingsScreen(
onSignOut: () async {
await client.auth.signOutDevice();
},
),
),
SignInWidget renders the standard Google sign-in button:

To change the button's theme or build a fully custom UI, see Customizing the UI.
If you run into issues, see the troubleshooting guide.
Publishing to production
Before going live, complete the following steps:
1. Verify your authorized domain
Google's Authorized domains field on the 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.
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 by adding the DNS TXT record Google provides. After verification completes, add the root to Authorized domains in the Google Auth Platform.
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 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://my-awesome-project.serverpod.space - Authorized redirect URIs:
https://my-awesome-project.serverpod.space
Replace the URL with your actual production web server address. On Serverpod Cloud, your project is served from https://<project-id>.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.
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 first and use its values below.
Pick the path that matches your deployment:
Self-hosted
Add googleClientSecret to the production: section of passwords.yaml with the production redirect URI:
production:
# ... existing keys ...
googleClientSecret: |
{
"web": {
"client_id": "your-client-id.apps.googleusercontent.com",
"client_secret": "your-client-secret",
"redirect_uris": ["https://my-awesome-project.serverpod.space"]
}
}
Alternatively, set the SERVERPOD_PASSWORD_googleClientSecret environment variable on your production server with the same JSON value.
Serverpod Cloud
Use https://<project-id>.serverpod.space as the redirect URI in the JSON. Save it to a file and use scloud password set with --from-file:
scloud password set googleClientSecret --from-file path/to/google-client-secret.json
Run this from your linked server project directory, or pass --project <project-id> on the call. See the Serverpod Cloud passwords guide for project linking and other options.
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.
If you use Google Play App Signing (the default for new apps), get the SHA-1 from the Play Console: Setup > App integrity > App signing key certificate. Make sure to use the app signing key SHA-1, not the upload key SHA-1.
If you manage your own release keystore, get the SHA-1 from it directly:
keytool -list -v -keystore your-release-key.jks -alias your-key-alias
Once you have the SHA-1, go back to your Android OAuth client in the Google Auth Platform and add it under SHA-1 certificate fingerprint.
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.
5. Publish the OAuth consent screen
While the app is in Testing mode, only the test users you added on the 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.