Peter
Peter Software Developer | Technical Writer | Actively helping users with their questions on Stack Overflow. Occasionally I post here and on other platforms.

Using Google Sign-in With Firebase In Flutter

Using Google Sign-in With Firebase In Flutter
Source Code Follow me on

In this article, we will add Firebase Authentication and Google Sign-in to a Flutter application, which will authenticate a user by logging in using the gmail account and then we will retrieve user information.

Get Started With Google Sign-in

This is the sixth article related to Firebase in Flutter, you can check the previous articles in the below links:

To know how to integrate Firebase with Flutter, you can check the first article in the above list. In the other two articles, I created a form using Flutter performed queries for the realtime database and authenticated users with Firebase, in the cloud firestore article, it was different code snippet related to Firestore and explaining each one. This article I will demonstrate how to use google_sign_in and firebase_auth.This article is aimed for the android phones.

Adding Firebase Auth And Google Sign-in To Flutter

As I said before, to check how to create a flutter project and add Firebase, then please check this article Get Started With Firebase in Flutter. Next, you need to add the following dependency to the pubspec.yaml file:

1
2
3
4
5
6
7
8
9
10
11
12
dependencies:
  cupertino_icons: ^1.0.8
  firebase_auth: ^5.1.4
  firebase_core: ^3.3.0
  flutter:
    sdk: flutter
  font_awesome_flutter: ^10.7.0
  google_sign_in: ^6.2.1

dev_dependencies:
  flutter_test:
    sdk: flutter

Click CTRL + S to save, and you have successfully added the above dependencies to your Flutter application!

Enable Google Sign-in

Now before working on the application, you need to navigate to the Firebase console and enable google sign-in. Therefore navigate to the Authentication tab and then click Sign-in method. You will find multiple providers, but for this tutorial you only need to enable the Google provider:

firebase auth google sign in flutter

When enabling, you will also be asked to provide project support email which will be the presented to users when they are authenticating with Google. If you want to authenticate using email/password then check this tutorial: Using Firebase Auth In Flutter.

Generate SHA-1 Fingerprint

This is an important step. To be able to use Google sign-in, then you need to generate the SHA-1 key. This key will be used by Firebase to create an OAuth2 client and API key for your app. Therefore in the terminal, execute:

1
2
cd android
./gradlew signingReport

which will give you the following output:

1
2
3
4
5
6
7
8
9
> Task :app:signingReport
Variant: debug
Config: debug
Store: /Users/peter/.android/debug.keystore
Alias: AndroidDebugKey
MD5: <md5-key>
SHA1: <sha1-key>
SHA-256: <sha256-key>
Valid until: Tuesday, December 1, 2048

Copy the SHA-1 key and navigate to the Firebase console, then go to the Project settings, and add the key as shown in the image below:

firebase auth google sign in flutter

Then download the google-services.json file again, and add it the project under android/app.

After that execute flutter clean. The above steps are really important, if not done correctly you will get the following error later on:

1
PlatformException(sign_in_failed, com.google.android.gms.common.api.ApiException: 10: , null)

Creating The Welcome Screen

The design of this application is based on this dribbble design by Ashlee Mckay. Even though, the design contains email/password field, for this tutorial we only care about the sign in with google.

First inside the main() method add the following:

1
2
3
4
5
void main() async{
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
  runApp(MyApp());
}

As usual, since we are using Firebase packages, then we need to call Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform) to configure it. Then inside the MyApp class, you need to do the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: Constants.title,
      initialRoute: '/',
      routes: Navigate.routes,
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
    );
  }
}

So here I created a util class called Constants which will contain all string values used. For the routes, I also created a Navigate class which will contain all the routes. The Navigate class:

1
2
3
4
5
6
7
class Navigate {
  static Map<String, Widget Function(BuildContext)> routes =   {
    '/' : (context) => WelcomePage(),
    '/sign-in' : (context) => SignInPage(),
    '/home'  : (context) => HomePage()
  };
}

Now, create a new file called welcome_page.dart. Inside that file you would have WelcomePage class which extends StatelessWidget:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class WelcomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    Size size = MediaQuery.of(context).size;
    User? result = FirebaseAuth.instance.currentUser;
    return Scaffold(
        backgroundColor: Constants.kPrimaryColor,
        body: AnnotatedRegion<SystemUiOverlayStyle>(
          value: Constants.statusBarColor,
          child: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Image.asset("assets/images/main-img.png"),

So here we use the MediaQuery to get the size of the screen, and we also use currentUser which will return the currently logged in user. Then create an instance of AnnotatedRegion, you need to use this class to be able to change the status bar and icon color. The statusBarColor is a constant value in the class Constants:

1
2
3
  static const statusBarColor = SystemUiOverlayStyle(
      statusBarColor: Constants.kPrimaryColor,
      statusBarIconBrightness: Brightness.dark);

Inside the Column widget, we would add all the children widget:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
 child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Image.asset("assets/images/main-img.png"),
                RichText(
                    textAlign: TextAlign.center,
                    text: TextSpan(children: <TextSpan>[
                      TextSpan(
                          text: Constants.textIntro,
                          style: TextStyle(
                            color: Constants.kBlackColor,
                            fontWeight: FontWeight.bold,
                            fontSize: 30.0,
                          )),
                      TextSpan(
                          text: Constants.textIntroDesc1,
                          style: TextStyle(
                              color: Constants.kDarkBlueColor,
                              fontWeight: FontWeight.bold,
                              fontSize: 30.0)),
                      TextSpan(
                          text: Constants.textIntroDesc2,
                          style: TextStyle(
                              color: Constants.kBlackColor,
                              fontWeight: FontWeight.bold,
                              fontSize: 30.0)),
                    ])),
                SizedBox(height: size.height * 0.01),
                Text(
                  Constants.textSmallSignUp,
                  style: TextStyle(color: Constants.kDarkGreyColor),
                ),
                SizedBox(height: size.height * 0.1),
                SizedBox(
                  width: size.width * 0.8,
                  child: OutlinedButton(
                    onPressed: () {
                      result == null
                          ? Navigator.pushNamed(
                              context, Constants.signInNavigate)
                          : Navigator.pushReplacementNamed(
                              context, Constants.homeNavigate);
                    },
                    child: Text(Constants.textStart),
                    style: ButtonStyle(
                        foregroundColor: WidgetStateProperty.all<Color>(
                            Constants.kPrimaryColor),
                        backgroundColor: WidgetStateProperty.all<Color>(
                            Constants.kBlackColor),
                        side: WidgetStateProperty.all<BorderSide>(
                            BorderSide.none)),
                  ),
                ),
                SizedBox(
                  width: size.width * 0.8,
                  child: OutlinedButton(
                    onPressed: () {},
                    child: Text(
                      Constants.textSignIn,
                      style: TextStyle(color: Constants.kBlackColor),
                    ),
                    style: ButtonStyle(
                        backgroundColor: WidgetStateProperty.all<Color>(
                            Constants.kGreyColor),
                        side: WidgetStateProperty.all<BorderSide>(
                            BorderSide.none)),
                  ),
                )
              ],
            ),

As you can see above, we use the RichText, so we can have multiple text with different color according to the design. We also use the SizeBox widget to add a space between different widgets. In the onPressed of the Get Started button, we add the following:

1
2
3
4
5
6
7
onPressed: () {
    result == null
        ? Navigator.pushNamed(
            context, Constants.signInNavigate)
        : Navigator.pushReplacementNamed(
            context, Constants.homeNavigate);
            },

This will check if current user is null, then navigate to the sign in page, else navigate to the home page and remove all routes from the stack. The above will give you the following screen:

firebase auth google sign in flutter

Note: You can also check if a user is logged in or not by using a splash screen as can be seen here

Creating The Google Sign-in Page

Now create a different page called sign_in_page.dart, and inside that page create a SignPage class:

1
2
3
4
5
6
7
8
9
10
11
12
13
class SignInPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    Size size = MediaQuery.of(context).size;
    OutlineInputBorder border = OutlineInputBorder(
        borderSide: BorderSide(color: Constants.kBorderColor, width: 3.0));
    return Scaffold(
        resizeToAvoidBottomInset: false,
        backgroundColor: Constants.kPrimaryColor,
        body: Center(
            child:
                Column(mainAxisAlignment: MainAxisAlignment.center, children: [
          Image.asset("assets/images/sign-in.png"),

As you can see here, we create a Scaffold widget, which will contain a Column widget and that widget will contain a list of widgets. After adding all the other widgets inside the column (check code on Github), then we create a StatefulWidget:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
class GoogleSignIn extends StatefulWidget {
  GoogleSignIn({Key? key}) : super(key: key);

  @override
  _GoogleSignInState createState() => _GoogleSignInState();
}

class _GoogleSignInState extends State<GoogleSignIn> {
  bool isLoading = false;

  @override
  Widget build(BuildContext context) {
    Size size = MediaQuery.of(context).size;
    return  !isLoading? SizedBox(
      width: size.width * 0.8,
      child: OutlinedButton.icon(
        icon: FaIcon(FontAwesomeIcons.google),
        onPressed: () async {
          setState(() {
            isLoading = true;
          });
          FirebaseService service = new FirebaseService();
          try {
           await service.signInwithGoogle();
           Navigator.pushNamedAndRemoveUntil(context, Constants.homeNavigate, (route) => false);
          } catch(e){
            if(e is FirebaseAuthException){
              showMessage(e.message!);
            }
          }
          setState(() {
            isLoading = false;
          });
        },
        label: Text(
          Constants.textSignInGoogle,
          style: TextStyle(
              color: Constants.kBlackColor, fontWeight: FontWeight.bold),
        ),
        style: ButtonStyle(
            backgroundColor:
                WidgetStateProperty.all<Color>(Constants.kGreyColor),
            side: WidgetStateProperty.all<BorderSide>(BorderSide.none)),
      ),
    ) : CircularProgressIndicator();
  }

The above StatefulWidget will also be called from the Column widget. Now as you can see above, inside the onPressed we use setState which will call the build() method with the new value of Loading. We also initialize the custom class FirebaseService() and call signInWithGoogle() which we will see in the next section.

The method signInwithGoogle() is asynchronous, therefore we use async/await to wait until it finishes. We also use it inside a try/catch. If an error occurs, it will call the showMessage() method which will show a dialog with the error:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  void showMessage(String message) {
    showDialog(
        context: context,
        builder: (BuildContext context) {
          return AlertDialog(
            title: Text("Error"),
            content: Text(message),
            actions: [
              TextButton(
                child: Text("Ok"),
                onPressed: () {
                  Navigator.of(context).pop();
                },
              )
            ],
          );
        });
  }

The above code will give you the following screen:

firebase auth google sign in flutter

Performing Google Sign-in

In the previous section, we called the following method service.signInwithGoogle();. First, create a folder called services and inside of it create a class called FirebaseService:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class FirebaseService {
  final FirebaseAuth _auth = FirebaseAuth.instance;
  final GoogleSignIn _googleSignIn = GoogleSignIn();

  Future<String?> signInwithGoogle() async {
    try {
      final GoogleSignInAccount? googleSignInAccount =
          await _googleSignIn.signIn();
      final GoogleSignInAuthentication googleSignInAuthentication =
          await googleSignInAccount!.authentication;
      final AuthCredential credential = GoogleAuthProvider.credential(
        accessToken: googleSignInAuthentication.accessToken,
        idToken: googleSignInAuthentication.idToken,
      );
      await _auth.signInWithCredential(credential);
    } on FirebaseAuthException catch (e) {
      print(e.message);
      throw e;
    }
  }

  Future<void> signOutFromGoogle() async{
    await _googleSignIn.signOut();
    await _auth.signOut();
  }
}

As you can see we initialize both FirebaseAuth and GoogleSignIn which will allows you to authenticate Google users. So first you need to call _googleSignIn.signIn(); which returns a Future<GoogleSignInAccount?>. The signIn() method will start the interactive sign-in process in which you choose a dialog is shown and you choose a gmail account. Then we call googleSignInAccount!.authentication which will retrieve the authentication token after sign in.

Now we have access to both the accessToken and the idToken, therefore we create a new GoogleAuthCredential from the provided tokens. Then, we finally call _auth.signInWithCredential(credential); which will sign in the user to Firebase with the given Google credentials. The reason we sign in to Firebase, so later when we call currentUser we can access the email/name/and photo url of the user.

Also, in the above class we have the method signOutFromGoogle(), which we will use to log out from both Firebase and Google sign-in.

Therefore, when we click the onPressed property discussed in previous section, we would get the following screen:

firebase auth google sign in flutter

Retrieve User Information

Now, we create another file called home_page.dart which will contain the HomePage class. Inside the class, we need to retrieve the current user by calling:

1
 User? user = FirebaseAuth.instance.currentUser;

Then inside the Column widget, we add the following widgets:

1
2
3
4
5
6
7
8
9
10
11
12
        body: Center(
            child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(user!.email!),
            Text(user!.displayName!),
            CircleAvatar(
              backgroundImage: NetworkImage(user!.photoURL!),
              radius: 20,
            )
          ],
        )))

Here we retrieve the email, name and the photo url of the user. The above code will give us the following screen:

firebase auth google sign in flutter

As you can see from the image, the app bar will also contain a logout button in which we will call the method service.signOutFromGoogle(); which is inside the FirebaseService class.

I hope you enjoyed reading this flutter tutorial, please feel free to leave any comments or feedback on this post!

 

Become a Patron!