Integrating Google Sign in with Serverpod: Authentication — Part 2
A Step-by-Step Guide to Integrating Google Sign in in Serverpod
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:
- A functioning Serverpod project with CLI and Docker, as covered in Part 1.
- A Google Cloud account for configuring Google Login.
- Appropriate SDKs and emulators for your desired platforms (Android, iOS, Web, MacOS, Windows, Linux).
- 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:
- Log in to Google Cloud Console: Navigate to the Google Cloud Console and log in with your Google account.
- Create a new project: Click on the project drop-down menu and select ‘New Project’. Give your project a name and select ‘Create’.
- 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’.
- 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’.
- Add Scopes: On the ‘Scopes’ page, add the scopes
.../auth/userinfo.email
and.../auth/userinfo.profile
click ‘Save and Continue’. - 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
- 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 origins
andAuthorized redirect URIs
fields blank for now. - 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
. - 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!
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 SignInWithGoogleButton
that 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.json
file 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!
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
- 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.
- Enter your Bundle ID: This can be found in xcode under Runner > General > Bundel Identifier. It usually follows the format
com.yourcompany.yourproject
. - Register your app’s bundle ID: In the form that appears, enter your app’s bundle ID in the ‘Bundle ID’ field.
- 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.
- Create your iOS client ID: Click ‘Create’ to finalize your iOS client ID.
- 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.
- Rename the file: Change the name of the file you just downloaded too
GoogleService-Info.plist
- 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.
- Include the file in your iOS project: Drag and drop the file into your xcode project.
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.
- Open your project’s
Info.plist
file: Navigate to theios/Runner
directory of your Flutter project and locate theInfo.plist
file. - 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 iscom.googleusercontent.apps.12345
. - 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:
- 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
- Copy SHA-1 Fingerprint: After generating the SHA-1, copy it from the terminal.
- Open Google Cloud Console: Go to your project in the Google Cloud Console.
- Navigate to Credentials: Under ‘APIs & Services’, choose ‘Credentials’.
- Access OAuth Client ID: Click on the OAuth 2.0 Client ID created earlier.
- Add Android Application: Click ‘Add an item’ under ‘Android application’.
- Input Package Name: Enter your package name found in
AndroidManifest.xml
(e.g.,package="com.example.yourappname"
). - Paste SHA-1 Fingerprint: Place the SHA-1 fingerprint in the corresponding field.
- 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:
- Configure your Credentials: In the Google Cloud Console, Go to APis & Services > Credentails > Your server credentails
- 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.
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.
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:
- 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.
- 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.
- 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.
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.