Google Sign-in in Flutter (without Firebase)

Google Sign-in in Flutter (without Firebase) with NodeJS Back-End

Google Sign-in in Flutter (without Firebase)
Google Cloud welcome page

TL;DR

This week i tried to add google sign-in to my app and it was the most frustrating task i did this Q , because most google documentations was either irrelevant or too confusing , so I’m writing this to help myself and others who would find themselves in the same situation.

steps:

  • Project in Google Cloud Console ⚙️
  • Flutter code 💻
  • Back-End APIs 🌐

Project in Google Cloud Console

steps:

  1. Create a Google Cloud Project 🛠️
  2. Configure the OAuth consent screen 🔐
  3. Configure Credentials 🆔
    3.0. Add google_sign_in to dependencies
    3.1. Server Client ID
    3.2. Web app Client ID
    3.3. Android Client ID
    3.4. IOS Client ID
  4. Publishing 🚀
    4.1. Add domains to Google Search Console
    4.2. Request to Publish in Google Cloud Console

1. Create a Google Cloud Project

Go to the Google Cloud Console (https://console.cloud.google.com/projectcreate) and create a new project.

Once the project is created, you’ll be redirected to the Google Cloud welcome page.

From the Quick access section, select “APIs & Services”:

APIs & Services main page

From the “APIs & Services” page, select “OAuth consent screen”:

OAuth consent screen page

and now the adventure begins 🧑‍🚀

If you are planning to publish your app, choose the “External” option and click “CREATE”:

OAuth consent/App information page

Enter the required information on the OAuth consent/app information page.

Note: if your Web App has a different URL, add it in the “Authorized domains” section
Scopes page

In this page if you don’t need any specific data, you don’t need to change anything

Test users page

If you want to publish your app to the public, you don’t have to change anything

Summery page

If everything is correct then just click “BACK TO DASHBOARD”

3. Configure Credentials

From the left side bar navigate to “Credentials”:

Credentials page
Note: I prefer to first create the server OAuth client ID and then create the client IDs for my apps. However, there is no functional difference between them.

3.0. Add google_sign_in to dependencies

Go to the google_sign_in page on the pub.dev website:

google_sign_in | Flutter Package
A Flutter plugin for Google Sign In. Android iOS Web Support SDK 16+ iOS 11+ Any To access Google Sign-In, you'll need…
https://pub.dev/packages/google_sign_in

Copy the version value next to the package name.

Open the “pubspec.yaml” file in your project’s main directory and add google_sign_in to the dependencies section:

dependencies: 
  ... 
  google_sign_in: ^6.1.0 
  ...
Replace “6.1.0” with the version you copied from pub.dev

Run the “flutter pub get” command in your terminal to fetch and update the dependencies

3.1. Server Client ID

Click on “CREATE CREDENTIALS”:

clicked CREATE CREDENTIALS

Pick the “OAuth client ID” option:

Create OAuth client ID page

Select the “Web application” type:

Create OAuth client ID page — selected type is Web application

Enter a name for the server client ID, you can leave the “Authorized JavaScript origins” and “Authorized redirect URIs” fields blank, and click on “CREATE”.

client ID is created

click on “DOWNLOAD JSON”. Save this file for later use in your server and Flutter app.

3.2. Web app Client ID

Click on “CREATE CREDENTIALS”:

clicked CREATE CREDENTIALS

Pick the “OAuth client ID” option:

Create OAuth client ID page

Select the “Web application” type:

Create OAuth client ID page — selected type is Web application

Enter a name for the web client ID, add you web app URLs to “Authorized JavaScript origins” field, and click on “CREATE”.

Note: if you want to test your code locally make sure to add a local url, example: “http://localhost:5000”
Note: if your server is using redirect urls to verify users add the URL to “Authorized redirect URIs” field.
client ID is created

click on “DOWNLOAD JSON”. Save this file for later use in your Flutter app.

3.3. Android Client ID

To generate a keystore file go to your terminal and then navigate to your flutter project directory, then navigate to the android directory

my terminal

Enter this command (for windows check here)

keytool -genkey -v -keystore <path-to-your-project>/android/app/androidkey.jks -keyalg RSA -keysize 2048 -validity 10000 -alias keyalias
Note: replace the “<path-to-your-project>” value by your project path

it would ask for a password , just input a password and them fill in the field based on your project (you can leave them empty)

Note: This command generates a keystore file named “androidkey.jks” in the “android/app” directory of your project. You can choose a different name and alias if you prefer.

after key was generated open the “android/app/build.gradle” file and add this part:

android {

...buildTypes {
       release {
           // TODO: Add your own signing config for the release build.
           // Signing with the debug keys for now, so `flutter run --release` works.
           signingConfig signingConfigs.debug
       }
       debug {
           signingConfig signingConfigs.debug
       }
   }...signingConfigs {
       debug {
           keyAlias 'keyalias'
           keyPassword <your-password>
           storeFile file('androidkey.jks')
           storePassword <your-password>
       }
   }
}

In the terminal, navigate to “android” directory and run the following command:

./gradlew signingReport

Then scroll to the top of the response and find this part:

Starting a Gradle Daemon (subsequent builds will be faster)

> Task :app:signingReport
Variant: debug
Config: debug
Store: <path-to-your-project>/android/app/androidkey.jks
Alias: keyalias
MD5: 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
SHA1: 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
SHA-256: 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
Valid until: Thursday, September 22, 2050
----------
...

Locate and copy the “SHA1” value.

Now go back to Google Cloud Console, Click on “CREATE CREDENTIALS”:

clicked CREATE CREDENTIALS

Pick the “OAuth client ID” option:

Create OAuth client ID page

Select the “Android” type:

Create OAuth client ID — selected type is Android

Past the SHA1 value and name the Client ID

To obtain the “Package name” value, open “android/app/src/main/AndroidManifest.xml”, in the first line copy the “package” value and past it in the “Package name” field and click “CREATE”:

client ID is created

click on “DOWNLOAD JSON”. Save this file for later use in your Flutter app.

3.4. IOS Client ID

…i will finish this later… 🫠

Publishing

4.1. Add domains to Google Search Console

Navigate to Google Search Console:

Google Search Console
Improve your performance on Google Search Search Console tools and reports help you measure your site's Search traffic…

Select “Domain” and enter you domain in the field and click “CONTINUE”

verify Ownership

Add this TXT record in your DNS configuration and wait for couple of minutes.

Note: if you use “cloudflare.com” to manage your DNS, this part would be way much easier and faster.
Note: if you use web hosting services (such as WHC) there is a hight chance that TXT doesn’t work for you, and remember to add the record in the cPanel and not in the web hosting DNS manager.

If everything works, you will see this Pop-up:

For Cloudflare users, this page would look like this:

verify Ownership for Cloudflare users

Click “START VERIFICATION” and will be redirected to the Cloudflare website

Cloudflare Authorize page

Click “Authorize” and Cloudflare will configure the records automatically.

If everything works, you will see this Pop-up:

Note: Repeat this process for all of your domains.

4.2. Request to Publish in Google Cloud Console

In Google Cloud navigate to “OAuth consent screen” and click “PUBLISH APP”:

OAuth consent screen

Click “CONFIRM” and wait for the Google’s response Email.

Note: if you clicked “CONFIRM” before verifying your domains or you forgot to add a domain and got an Email telling you the verification failed, after adding the domains, send this email to Google’s Trust and Safety team:

Preferably send this as a reply to an Email with this Subject:

OAuth Verification Request for Project <project-name>

If you couldn’t find it use this Subject:

Request for Google Cloud Project Verification and Publication

Reply with this Email:

Hi, 
Dear Google Trust & Safety Team, 
 
 
I am writing to inform you that I have successfully completed the domain verification process in Google Search Console. As a result, I would like to request the verification and publication of my Google Cloud Project associated with the domains. 
 
I kindly request your assistance in verifying and publishing my Google Cloud Project. I understand the importance of adhering to Google's Trust & Safety policies, and I assure you that my project complies with all the necessary guidelines and regulations. 
 
 
If there are any specific steps or additional information required from my end, please let me know, and I will promptly provide all the necessary details. 
 
 
Best regards, 
 
<your-teams-name>

Flutter code

Add this to your “constants.dart” file:

import 'package:flutter/foundation.dart' show kIsWeb; 
 
... 
 
class AppKey{ 
  static const String googleServerClientId = '<your-server-clientID>.apps.googleusercontent.com'; 
} 
 
const GOOGLE_CLIENT_ID_WEB = '<your-web-clientID>.apps.googleusercontent.com'; 
 
String GoogleClientID() { 
  if (kIsWeb) { 
    // running on the web! 
    return GOOGLE_CLIENT_ID_WEB 
  } 
  return ''; 
}
Note: replace these values “<your-server-clientID>” and “<your-web-clientID>”
import 'package:get/get.dart'; 
import 'package:google_sign_in/google_sign_in.dart'; 
import 'package:<project-name>/core/constants.dart'; 
 
class GoogleController extends GetxController { 
  Rx<pageState> status = pageState.initial.obs; 
  late GoogleSignIn _googleSignIn; 
 
  void initAuth() { 
    final String googleClientId = GoogleClientID(); 
    // this is because we only need to config the `clientId` for web app, 
    // android and ios are configured in their specific config files  
    if (googleClientId == '') { 
      _googleSignIn = GoogleSignIn(serverClientId: AppKey.googleServerClientId); 
    } else { 
      _googleSignIn = GoogleSignIn( 
        serverClientId: AppKey.googleServerClientId, 
        clientId: googleClientId, 
      ); 
    } 
  } 
 
  void authWithGoogle({ 
    required bool isSignIn, 
  }) async { 
    status(pageState.loading); 
    try { 
      /*  
      TODO: remove this after testing was finished, 
      this lets you pick your account in every login attempt  
      */ 
      await _googleSignIn.signOut(); 
 
      GoogleSignInAccount? googleSignInAccount = await _googleSignIn.signIn(); 
      GoogleSignInAuthentication? _googleAuth = await googleSignInAccount!.authentication; 
      if (googleSignInAccount != null) { 
        if (googleSignInAccount.serverAuthCode != null && googleSignInAccount.serverAuthCode!.isNotEmpty) { 
          print(_googleAuth.idToken.toString()); 
          print(googleSignInAccount.email); 
          print(googleSignInAccount.displayName); 
          // TODO: here you can send the login request to your server's API 
          // NOTE: you only need to send the `_googleAuth.idToken.toString()` 
          await _googleSignIn.signOut(); 
          status(pageState.loaded); 
        } else { 
          status(pageState.error); 
        } 
      } else { 
        status(pageState.error); 
      } 
    } catch (e) { 
      status(pageState.error); 
    } 
  } 
}
Note: replace the value of “<project-name>”

Back-End APIs

I wrote my auth service in nodeJS. However, there isn’t a big difference between different languages. Refer to google documentation for you specific language here:

Google Sign-In for server-side apps | Authentication | Google Developers
Edit description

Add the required dependency with:

npm install google-auth-library

Add these APIs to your user routes:

var express = require('express'); 
const cors = require('cors'); 
const helmet = require('helmet'); 
const { OAuth2Client } = require('google-auth-library'); 
 
var config = require('../config/config.json'); 
 
var app = module.exports = express.Router(); 
 
// adding Helmet to enhance your Rest API's security 
app.use(helmet()); 
 
app.use( 
    cors({ 
        origin: config.allowedOrigin, 
        methods: ["GET", "POST"] 
    }) 
); 
 
app.post(config.apiVersionPrefix + '/users/signup-google-auth', async function(req, res) { 
    if (!req.body.tokenId) { 
        return res.status(400).send({ 
            message: "Please fill in all the fields", 
        }); 
    } 
 
    const client = new OAuth2Client(config.googleAuth.ServerClientID); 
 
    const ticket = await client.verifyIdToken({ 
        idToken: req.body.tokenId, 
    }); 
 
    const response = ticket.getPayload(); 
 
    if (response.email_verified !== true) { 
        return res.status(400).send({ message: 'Bad Request' }); 
    } 
     
    if (response.iss !== 'https://accounts.google.com' && response.aud !== config.googleAuth.ServerClientID) { 
        return res.status(400).send({ message: 'Bad Request' }); 
    } 
 
    // check if user already exists 
    var mongoRes = await usersMongoClient.findByEmail(response.email) 
    if (mongoRes !== null) { 
        return res.status(400).send({ 
            message: "User already exists", 
        }); 
    } 
 
    // TODO: check if `response.sub` is already a taken username, if `true` add a rnadom number to the end and then check again 
    // TODO: download the image and upload it to our server's S3 storgae and save the saved object ID instead 
 
    const newUser = new UserDomain(); 
    newUser.Email = response.email; 
    newUser.Username = response.sub; 
    newUser.Images = [response.picture]; 
    newUser.CreatedAt = new Date(); 
    newUser.Fullname = response.given_name; 
    newUser.IsEmailVerified = true; 
 
    // save user in database 
    await usersMongoClient.addUser(newUser); 
 
    var mongoRes = await usersMongoClient.findByEmail(response.email) 
 
    return res.status(201).send({ 
        id_token: authUtils.createIdToken(mongoRes.username), 
        access_token: authUtils.createAccessToken(mongoRes.username, mongoRes._id) 
    }); 
}); 
 
app.post(config.apiVersionPrefix + '/users/login-google-auth', async function(req, res) { 
    if (!req.body.tokenId) { 
        return res.status(400).send({ 
            message: "Please fill in all the fields", 
        }); 
    } 
     
    const client = new OAuth2Client(config.googleAuth.ServerClientID); 
 
    const ticket = await client.verifyIdToken({ 
        idToken: req.body.tokenId, 
    }); 
 
    const response = ticket.getPayload(); 
 
    if (response.email_verified !== true) { 
        return res.status(400).send({ message: 'Bad Request' }); 
    } 
     
    if (response.iss !== 'https://accounts.google.com' && response.aud !== config.googleAuth.ServerClientID) { 
        return res.status(400).send({ message: 'Bad Request' }); 
    } 
 
    // check if user exists 
    var mongoRes = await usersMongoClient.findByEmail(response.email) 
    if (mongoRes === null) { 
        return res.status(400).send({ 
            message: "User doesn't exists", 
        }); 
    } 
 
    return res.status(201).send({ 
        id_token: authUtils.createIdToken(mongoRes.username), 
        access_token: authUtils.createAccessToken(mongoRes.username, mongoRes._id) 
    }); 
});

Your config file should look like this:

{ 
    ... 
 
    "googleAuth": { 
        "ServerClientID":"<your-server-clientID>.apps.googleusercontent.com" 
    } 
}

Resources:

OAuth API verification FAQs
If your app uses Google APIs to access Google users' data, you might have to complete a verification process before you…
Troubleshooting | Public DNS | Google Developers
If you have problems resolving domains using Google Public DNS, first check the Google Public DNS homepage at…
Did anyone manage to get the id token from google sign in (Flutter)
The issue may be related to not using firebase. There is a google-services.json file which is given to you when you…
Google Search Console verification - 2019
Hi all, I recently just created my online store at www.narrawatches.com and I am applying for a Google Search Console…
OAuth API verification FAQs
If your app uses Google APIs to access Google users' data, you might have to complete a verification process before you…
google-auth-library
This is Google's officially supported node.js client library for using OAuth 2.0 authorization and authentication with…
Google Cloud Platform
Google Cloud Platform lets you build, deploy, and scale applications, websites, and services on the same infrastructure…
Flutter: Implementing Google Sign In
In this article, I will be showing how to set up and implement Google Sign In using Firebase Authentication.
How to know if user is authenticated with Google auth using Firebase on Nodejs?
Thanks for contributing an answer to Stack Overflow! Please be sure to answer the question. Provide details and share…
google_sign_in | Flutter Package
A Flutter plugin for Google Sign In. Android iOS Web Support SDK 16+ iOS 11+ Any To access Google Sign-In, you'll need…
OAuth API verification FAQs
If your app uses Google APIs to access Google users' data, you might have to complete a verification process before you…
Google Cloud Platform
Google Cloud Platform lets you build, deploy, and scale applications, websites, and services on the same infrastructure…
Did anyone manage to get the id token from google sign in (Flutter)
The issue may be related to not using firebase. There is a google-services.json file which is given to you when you…

IOS :

GoogleService-Info.plist file not found and clientId was not provided programmatically
Thanks for contributing an answer to Stack Overflow! Please be sure to answer the question. Provide details and share…
flutter google_sign_in crash : __exceptionPreprocess + 294
I am using the google_sign_in plugin in a flutter app to sign in. Using code from the example The code for signing in…
[google_sign_in] version 5 and later crashes and terminate on iOS with…
Steps to Reproduce Use google_sign_in 5.0.4 or 5.0.0 or 5.4.2 It was working in versions before 5, I just updated and…
flutter google sign-in crashes ios app, but android works fine · Issue #104422 · flutter/flutter
I'm having the same problem with Google sign-in on the iOS App. The Android app runs perfectly. I'm using…
🐛 [google_sign_in] My iOS app crashes when I click the "Sign in with Google" button · Issue #4983…
You can't perform that action at this time. You signed in with another tab or window. You signed out in another tab or…
Flutter: Implementing Google Sign In
In this article, I will be showing how to set up and implement Google Sign In using Firebase Authentication.