Integrating Google Sign in with Serverpod: Authentication — Part 2

A Step-by-Step Guide to Integrating Google Sign in in Serverpod

Isak
Serverpod
12 min readMay 29, 2023

--

Authentication Series

Part 1 — Email and Password Authentication
Part 2 — Google Authentication
Part 2.5 — Google API
Part 3 — Apple Authentication

Introduction

In the first part of our series, we delved into the fundamental aspects of Serverpod and set up an authentication system using email and password. We employed the Serverpod_auth module for this purpose, which offered a seamless backend and frontend integration for our Flutter application.

As we move forward in our journey with Serverpod, we will explore another pivotal feature of modern applications — third-party logins. In this tutorial, specifically, we will focus on Google Login integration. By allowing users to sign in with their existing Google accounts, we can provide a more streamlined, convenient, and secure authentication experience.

In this second part of the series, we will guide you step-by-step on how to integrate Google Login with Serverpod for your Flutter application. We will set up the necessary configurations in Google Cloud Project, modify our Serverpod_auth module to handle Google Login, implement platform-specific client-side integrations for Android, iOS, Web, MacOS, Windows, and Linux.

If you didn’t checkout Part 1 we recommend you at least complete setting up the project and auth module before moving on to this tutorial.

The complete example project we are creating in this tutorial can be found here

Let’s get started!

Prerequisite

Before proceeding with this tutorial, ensure you have:

  1. A functioning Serverpod project with CLI and Docker, as covered in Part 1.
  2. A Google Cloud account for configuring Google Login.
  3. Appropriate SDKs and emulators for your desired platforms (Android, iOS, Web, MacOS, Windows, Linux).
  4. A database viewer like Postico2, PgAdmin, or DBeaver. We’ll use Postico2 in this tutorial.

With these elements in place, you’re prepared to integrate Google Login with Serverpod.

Setting up the Google Cloud Project

To implement Google Login, we need to create a Google Cloud Project and obtain the OAuth 2.0 credentials. Follow these steps to set up the project:

  1. Log in to Google Cloud Console: Navigate to the Google Cloud Console and log in with your Google account.
  2. Create a new project: Click on the project drop-down menu and select ‘New Project’. Give your project a name and select ‘Create’.
  3. Enable Peoples API: On the dashboard, navigate to the ‘Library’ section under ‘APIs & Services’. Search for ‘Google People API’, select it, and click on ‘Enable’.
  4. Create OAuth consent screen: Go to ‘OAuth consent screen’ under ‘APIs & Services’. Choose ‘External’ for user type, then click ‘Create’. Fill in the required fields, including ‘App name’, ‘User support email’, and ‘Developer contact information’. Click ‘Save and Continue’.
  5. Add Scopes: On the ‘Scopes’ page, add the scopes .../auth/userinfo.email and .../auth/userinfo.profile click ‘Save and Continue’.
  6. Add Test Users: On the ‘Test Users’ page, add your Google account email as a test user, then click ‘Save and Continue’.

Your Google Cloud Project is now ready, but we still need to create the credentials for your server and your flutter apps.

Server Integration of Google Login

  1. Create Credentials: Navigate to ‘Credentials’ under ‘APIs & Services’. Click ‘Create Credentials’ and select ‘OAuth client ID’. Configure the OAuth client as a ‘Web application’. Name your client and leave the Authorized JavaScript originsand Authorized redirect URIs fields blank for now.
  2. Obtain the JSON credentials: After creating the credentials, you’ll be provided with an option to download the secrets as a json. Click the “DOWNLOAD JSON” button. Rename the file to google_client_secret.json.
  3. Add secret to Serverpod: Move the secret file into your server project and put it under config/google_client_secret.json. Serverpod will by default look for this file to interact with google.

Your server is now ready to use google login! It is that simple, let’s look at what we need to do client side!

The google credentials that we will create

Integrating Google Login into the Flutter App

Now we will be updating our Flutter app to include the Google Sign-In option. This will involve adding a new dependency and modifying the SignInPage widget we created in the previous tutorial.

Adding the Dependency: To begin with, we need to add the serverpod_auth_google_flutter package to our Flutter project. This can be done by including the package in the pubspec.yaml file of your project:

dependencies:
flutter:
sdk: flutter
serverpod_auth_google_flutter: ^latest_version

Be sure to replace latest_version with the current version of the serverpod_auth_google_flutter package. After adding the dependency, run flutter pub get in your terminal to fetch the package.

Remember that all serverpod dependencies should use the same version!

Updating the SignInPage Widget:
Next, we’ll add the SignInWithGoogleButtonthat gets shipped with serverpod_auth_google_flutter:

SignInWithGoogleButton(
caller: client.modules.auth,
serverClientId: _googleServerClientId,
redirectUri: Uri.parse('http://localhost:8082/googlesignin'),
),

The SignInWithGoogleButton widget takes in three parameters: caller, which should be client.modules.auth, serverClientId, which needs to be the client_id from your config/google_client_secret.jsonfile you added to the server. Last we have redirectUri, this field is only relevant for the web integration, for now we add http://localhost:8082/googlesignin. We will look more closely at how this works later.

Modify the SignInPage widget that we created in the previous tutorial and add the SignInWithGoogleButton. Here's how the updated SignInPage widget should look:

const _googleServerClientId = '<Your server_client_id>';

class SignInPage extends StatelessWidget {
const SignInPage({Key? key}) : super(key: key);

@override
Widget build(BuildContext context) {
return Center(
child: Dialog(
child: Container(
width: 260,
padding: const EdgeInsets.all(16),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
SignInWithEmailButton(
caller: client.modules.auth,
),
SignInWithGoogleButton(
caller: client.modules.auth,
serverClientId: _googleServerClientId,
redirectUri: Uri.parse('http://localhost:8082/googlesignin'),
),
],
),
),
),
);
}
}

With these changes in place, your Flutter app should now have a functioning Google Sign-In button alongside the Email Sign-In button. But to complete the setup we have to add the client credentials!

The google sign in button in our flutter app

Platform-Specific Client Integration of Google Login

In this section, we’ll delve into the platform-specific setup for Google Login integration, starting with iOS.

On mobile there are two options you can use, either place the google credentials in a json file in your project, or you can send in the clientId along with the serverClientId in your sign in button, like so:

var _clientId = '<your client_id>'

SignInWithGoogleButton(
caller: client.modules.auth,
clientId: _clientId,
serverClientId: _googleServerClientId,
redirectUri: Uri.parse('http://localhost:8082/googlesignin'),
),

For the rest of the tutorial we will show how to set this up with the json file. But keep in mind that the above solution is just as valid.

iOS

  1. Create a new iOS client ID: From the same page you created the server credentials. Click ‘Create Credentials’ and select ‘OAuth client ID’. Choose ‘iOS’ as the Application type.
  2. Enter your Bundle ID: This can be found in xcode under Runner > General > Bundel Identifier. It usually follows the format com.yourcompany.yourproject.
  3. Register your app’s bundle ID: In the form that appears, enter your app’s bundle ID in the ‘Bundle ID’ field.
  4. Add App Store ID and Team ID (optional): If you plan to release your app on the App Store, it’s a good idea to fill in the ‘App Store ID’ and ‘Team ID’ fields. You can find this information in your Apple Developer account.
  5. Create your iOS client ID: Click ‘Create’ to finalize your iOS client ID.
  6. Obtain your iOS Client ID and Secret: Once created, you’ll see your new iOS client ID in the list of ‘OAuth 2.0 Client IDs’. Click the download icon to download a JSON file containing your Client ID and Secret.
  7. Rename the file: Change the name of the file you just downloaded too GoogleService-Info.plist
  8. Move the file into your project folder: To avoid any future issues move the file from your downloads folder into your ios project folder. If you do not do this before next step, XCode will reference the file from your download folder.
  9. Include the file in your iOS project: Drag and drop the file into your xcode project.
Drag and drop the GoogleService-Info.json into XCode under Runner/Runner

Add the Server Client ID: Open GoogleService-Info.plist in your editor, check if there is a key called SERVER_CLIENT_ID if not add it. The value should be the client id from your server credentials.

<dict>
...
<key>SERVER_CLIENT_ID</key>
<string>your_server_client_id</string>
</dict>

Next we need to modify your project’s Info.plist file.

  1. Open your project’s Info.plist file: Navigate to the ios/Runner directory of your Flutter project and locate the Info.plist file.
  2. Add Google Sign-In URL scheme: You will need to register your reversed client ID as a URL scheme for your app. Your reversed client ID is your client ID with the order of the domain components reversed. For example, if your client ID is 12345.apps.googleusercontent.com, then your reversed client ID is com.googleusercontent.apps.12345.
  3. Add the following lines, replacing your_reversed_client_id with your actual reversed client ID:
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLSchemes</key>
<array>
<string>your_reversed_client_id</string>
</array>
</dict>
</array>

With these changes, your iOS application should be ready to handle Google Sign-In. Remember to test the functionality on an iOS emulator or device to ensure everything works as expected.

Note: If you have any social logins in your app you also need to integrate “Sign in with Apple” to publish your app to the app store. (Read more)

Android

In order for the Google Login to work on Android, we need to create a SHA-1 fingerprint and register it in our Google Cloud Project. Follow these steps:

  1. Generate SHA-1 Fingerprint: Google Login requires an SHA-1 fingerprint of your Android app. Open your terminal and navigate to the android directory of your Flutter project. Run the following command:
./gradlew signingReport

This command will generate a report which includes the SHA-1 fingerprint for the debug key. This key is typically located at ~/.android/debug.keystore.

Note: When doing this for a production app you need to get the SHA-1 key from your production keystore! This can be done running this command: (more info)

keytool -list -v -keystore /path/to/keystore
  1. Copy SHA-1 Fingerprint: After generating the SHA-1, copy it from the terminal.
  2. Open Google Cloud Console: Go to your project in the Google Cloud Console.
  3. Navigate to Credentials: Under ‘APIs & Services’, choose ‘Credentials’.
  4. Access OAuth Client ID: Click on the OAuth 2.0 Client ID created earlier.
  5. Add Android Application: Click ‘Add an item’ under ‘Android application’.
  6. Input Package Name: Enter your package name found in AndroidManifest.xml (e.g., package="com.example.yourappname").
  7. Paste SHA-1 Fingerprint: Place the SHA-1 fingerprint in the corresponding field.
  8. Create Application: Finalize by clicking ‘Create’.

Download the Google Services JSON: After adding the Android application, you will see a button ‘Download JSON’ on the top of the page. Download the file and place it in your project under android/app/.

Rename the file:google-services.json

Try it out on your android emulator / device! Keep in mind that you cannot use localhost as the server address on android. Both the emulator and a hardware device uses a different network address. Instead replace the host string you gave the client with your development machines local ip address (make sure the android device and your computer are on the same network).

client = Client(
// Use a local address for android, for example:
'http://192.168.43.44:8080/',
authenticationKeyManager: FlutterAuthenticationKeyManager(),
)..connectivityMonitor = FlutterConnectivityMonitor();

You can find your local ip address by running ifconfig on macos and linux or ipconfig on windows, in the terminal.

Web

There is no need of supplying a separate clientId for your web client. Your primary requirement is providing the serverClientId and setting up a redirect page, as detailed later in this section. But we have to modify the server credentials we created earlier. Here’s the process:

  1. Configure your Credentials: In the Google Cloud Console, Go to APis & Services > Credentails > Your server credentails
  2. Authorize JavaScript Origins and Redirect URIs: This includes the webserver URI, the Flutter application’s URI, and the full path to the redirect page. These URIs are crucial as they are the only ones authorized to make requests and receive responses.
Example setup of the authorized URIs

Where localhost:8082 is the webserver localhost:49660 is our flutter app and localhost:8082/googlesignin is the redirect page. In production you have to use your own domain here as well.

Note: If you have not configured this correctly you will get an error page when opening the login page.

Example of an error if your redirect / javascript origins are not configured correctly.

The subsequent steps will guide you in setting up the server and handling the redirect URI.

Set up the redirect route in your server: Inside the run method of your server.dart file, add the following line:

pod.webServer.addRoute(auth.RouteGoogleSignIn(), '/googlesignin');

Where auth comes from:

import 'package:serverpod_auth_server/module.dart' as auth

A reminder for the Flutter app’s Google Sign-In Button:

Use the serverClientId for the SignInWithGoogleButton parameters:

SignInWithGoogleButton(
caller: client.modules.auth,
serverClientId: _googleServerClientId,
// clientId can be null for Flutter web application
clientId: null,
redirectUri: Uri.parse('http://localhost:8082/googlesignin'),
),

The redirectUri should match the path you set in your server and the one inside your credentials in google cloud console. If the webhost path is /googlesignin the redirectUri should also be https://example.com/googlesignin.

There we go! Now it should all work, try it out! Remember to restart the server and reload your web app. You also need to launch the flutter app on the same port as you defined in the google credential origins.

You can specify the port by running flutter run -d chrome --web-port=49660.

How it works:

When you sign in, a popup is created with the Google sign-in page. After the sign-in is completed, the redirectUri is used. The Flutter plugin will wait for a web event with the serverAuthCode from this popup. The redirected page will contain this code in the URL and will send it back to the plugin and then automatically close the popup. The code is then used to authenticate yourself with the serverpod backend.

If you would like to modify the redirect page you could create your own backend widget, here is the implementation of the one we just used.

<html>
<head>
<script>
function findParam(name) {
let result = null;
location.search
.substr(1)
.split("&")
.forEach(function (item) {
const tmp = item.split("=");
if (tmp[0] === name) result = decodeURIComponent(tmp[1]);
});
return result;
}

function returnToWebClient() {
const code = findParam('code');
window.opener.postMessage(code, '*');
window.close();
}

returnToWebClient();
</script>
</head>

<body>
</body>

</html>

This script looks for the serverAuthCode ('code' in this case) in the URL parameters, and sends it back to the waiting Flutter plugin, thus completing the sign-in process.

Desktop

As of today, there’s no official support for Google Login integration on desktop platforms within Serverpod or the google_sign_in package. However, if you're eager to implement this, you can take a look at Social Authentication in Flutter Desktop Apps for detailed instructions on setting up Google Login for desktop platforms.

Note: This solution involves deep linking which may add complexity to your app.

Verifying User Creation in the Database

Once you’ve completed the steps of integrating Google Sign-In with your Flutter application, it’s crucial to ensure that user data is being correctly stored and retrieved from your database. Here’s how to verify user creation in your database:

  1. Sign in a User: The first step is to attempt to sign in a user through your application. After the user signs in with Google, the Flutter application should handle the login data and send it to your server.
  2. Check Server Logs: The server should then create a user in the database if one does not already exist. Check the server logs to ensure the server is receiving the user data and no errors are occurring during user creation.
  3. Inspect the Database: Use your database management tool to manually inspect the user table in the database. Ensure that the user data is being correctly inserted into the table. Check the serverpod_user_info table for the user data.
After you login you should see a new row with data here

Conclusion

To wrap up, throughout this guide, we’ve successfully incorporated Google Sign-In into our Flutter application. The integration, which was tailored for the web, also extended to Android and iOS, demonstrating the multi-platform capabilities of Flutter.

Having Google Sign-In in your application provides a seamless and secure authentication system, and we hope this guide has helped you implement it successfully in your Flutter application. Happy coding!

In the next part of this series we will take a look at integrating sign in with Apple.

--

--