Authenticating users is one of those capabilities you’ll always require when creating an interactive application, be it a mobile or web app. User authentication helps filter out unauthorised people from accessing or utiizing certain resources. One way is that you can roll out your own authentication mechanism that suits your app. Or even better you can utilize battle test authentication APIs that we are provided for free.

One of the easiest yet secure ways to authenticate users is just by utilizing the Google Sign in APIs provided for free by google. This is both safe, scalable and free. An it is the aim of this tutorial to look at some open source projects that allow us implement Google sign-in as a form of authentication. You will need Firebase Authentication APIs to do this.

Obviously our framework is flutter. Thus the code can be targeted at both iOS and Android. The code is written in Dart programming language. Note that you need a Google account to be able to implement Google sign in.

Let’s start.

Example 1 – Firebase Google Sign In in Flutter

Let’s look at our first example. We’ll have three files:

  1. home.dart
  2. user.dart
  3. main.dart

(a). pubspec.yaml

First we need a few dependencies. So navigate over to pubspec.yaml and add the following:

dependencies:
  flutter:
    sdk: flutter
  google_sign_in:
  firebase_auth:

  # The following adds the Cupertino Icons font to your application.
  # Use with the CupertinoIcons class for iOS style icons.
  cupertino_icons: ^0.1.0

You can see firebase_auth and google_sign_in have been added as dependencies.

(b). user.dart

Create a user widget based on the StatelessWidget class:

Start by importing the following pacakages:

import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:meta/meta.dart';

The create the class, making it extend the StatelessWidget class:

class User extends StatelessWidget {

Now define the following instance fields:

  VoidCallback onLogout;
  String username;
  FirebaseUser user;

Then define a constructor with the following parameters:

  User({Key key, @required this.onLogout, @required this.user})
      : super(key: key);

You can see a Callback and a FirebaseUser object are being passed and are actually required to be passed.

Let’s now override the build() method:

  @override
  Widget build(BuildContext context) {

and return a Scaffold object:

    return new Scaffold(

Inside the Scaffold constructor first pass the appbar:

      appBar: new AppBar(
        title: new Text("Welcome"),
        actions: <Widget>[
          new IconButton(
              icon: new Icon(Icons.exit_to_app), onPressed: this.onLogout)
        ],
      ),

Then the body:

      body: new Container(
          padding: const EdgeInsets.all(20.0),
          child: new Center(
              child: new Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              new Image.network(user.photoUrl),
              new Text(
                user.displayName,
                textScaleFactor: 1.5,
              ),
            ],
          ))),
    );
  }

You can see the body of this user widget will contain an Image widget to load image from network and Text widget to render the user’s display name.

Here is the full code for the user.dart file:

import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:meta/meta.dart';

class User extends StatelessWidget {
  User({Key key, @required this.onLogout, @required this.user})
      : super(key: key);

  VoidCallback onLogout;
  String username;
  FirebaseUser user;

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text("Welcome"),
        actions: <Widget>[
          new IconButton(
              icon: new Icon(Icons.exit_to_app), onPressed: this.onLogout)
        ],
      ),
      body: new Container(
          padding: const EdgeInsets.all(20.0),
          child: new Center(
              child: new Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              new Image.network(user.photoUrl),
              new Text(
                user.displayName,
                textScaleFactor: 1.5,
              ),
            ],
          ))),
    );
  }
}

(c). home.dart

Start by adding imports:

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:meta/meta.dart';

Make our Home class extend the StatelessWidget class:

class Home extends StatelessWidget {

Define several instance fields:

  final VoidCallback onSignin;
  final VoidCallback onLogout;
  bool showLoading = false;

Define the Home constructor making it receive several parameters:

  Home(
      {Key key,
      @required this.onSignin,
      @required this.onLogout,
      @required this.showLoading})
      : super(key: key);

Come override the build() method making it extend return a Scaffold object:

  @override
  Widget build(BuildContext context) {
    return new Scaffold(

Pass the AppBar as the first parameter in the Scaffold constructor.

Now specify the body:

      body: new Container(
          padding: const EdgeInsets.all(20.0),
          child: new Center(
            child: new Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                showLoading
                    ? new CircularProgressIndicator()
                    : new RaisedButton(
                        onPressed: this.onSignin,
                        child: new Text("Sign In"),
                        color: Colors.lightBlueAccent,
                      ),
                //new RaisedButton(onPressed: this.onLogout, child: new Text("Logout"), color: Colors.amberAccent),
              ],
            ),
          )),
    );
  }
}

You can see a CircularProgressIndicator will be rendered while the sign-in is in progress.

Here’s the full code for the home.dart:

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:meta/meta.dart';

class Home extends StatelessWidget {
  Home(
      {Key key,
      @required this.onSignin,
      @required this.onLogout,
      @required this.showLoading})
      : super(key: key);

  final VoidCallback onSignin;
  final VoidCallback onLogout;
  bool showLoading = false;

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(title: new Text("Sign In")),
      body: new Container(
          padding: const EdgeInsets.all(20.0),
          child: new Center(
            child: new Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                showLoading
                    ? new CircularProgressIndicator()
                    : new RaisedButton(
                        onPressed: this.onSignin,
                        child: new Text("Sign In"),
                        color: Colors.lightBlueAccent,
                      ),
                //new RaisedButton(onPressed: this.onLogout, child: new Text("Logout"), color: Colors.amberAccent),
              ],
            ),
          )),
    );
  }
}

(d). main.dart

The last file is the main.dart file.

Agains start by specifying the imports:

import 'dart:async';

import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:google_sign_in/google_sign_in.dart';

import 'home.dart';
import 'user.dart';

Then define the main function:

void main() {
  runApp(new App());
}

Create the App class we’ve instantiated above:

class App extends StatefulWidget {
  AppState createState() => new AppState();
}

Now create the AppState by extending the State class:

class AppState extends State<App> {

Then define instance fields including the GoogleSignin class:

  String _username = "";
  Widget currentPage;
  GoogleSignIn googleSignIn;
  Widget userPage;

Now override the initState() method:

  @override
  void initState() {
    super.initState();

Inside the initState() instantiate the Home class:

    userPage = new Home(
      onSignin: () {
        _signin();
        print("Sign");
      },
      onLogout: _logout,
      showLoading: false,
    );
  }

Now come create an asynchronous method to log us in:

  Future<FirebaseUser> _signin() async {

You can see its returning a Future object with a generic parameter of FirebaseUser class.

Inside the method reset the state of the home class:

    setState(() {
      userPage = new Home(onSignin: null, onLogout: _logout, showLoading: true);
    });

Then obtain the instance of FirebaseAuth:

    FirebaseAuth _auth = FirebaseAuth.instance;

Now create a try-catch block:

    try {

Then instantiate the GoogleSignIn class:

      googleSignIn = new GoogleSignIn();

Now perform the log in:

      GoogleSignInAccount googleSignInAccount = await googleSignIn.signIn();
      GoogleSignInAuthentication gauth =
          await googleSignInAccount.authentication;
      FirebaseUser user = await _auth.signInWithGoogle(
        accessToken: gauth.accessToken,
        idToken: gauth.idToken,
      );

      setState(() {
        _username = user.displayName;
        userPage = new User(
          onLogout: _logout,
          user: user,
        );
      });

      return user;

You can see a FirebaseUser object is being returned above.

In case of any exception catch it and print it out:

    } catch (e) {
      print(e.toString());
    }
    return null;
  }

What about loggin out? Well come create another method:

  void _logout() async {

Now to sign out simply invoke the signOut() method of the GoogleSignIn class:


    await googleSignIn.signOut();

Then reset the state:

    setState(() {
      userPage = new Home(
        onSignin: () {
          _signin();
          print("Sign");
        },
        onLogout: _logout,
        showLoading: false,
      );
    });

    print("Logged Out");
  }

Finally don’t forget to override the build() method:

  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      home: userPage,
    );
  }
}

Here is the full code for main.dart:

import 'dart:async';

import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:google_sign_in/google_sign_in.dart';

import 'home.dart';
import 'user.dart';

void main() {
  runApp(new App());
}

class App extends StatefulWidget {
  AppState createState() => new AppState();
}

class AppState extends State<App> {
  String _username = "";
  Widget currentPage;
  GoogleSignIn googleSignIn;
  Widget userPage;

  @override
  void initState() {
    super.initState();
    userPage = new Home(
      onSignin: () {
        _signin();
        print("Sign");
      },
      onLogout: _logout,
      showLoading: false,
    );
  }

  Future<FirebaseUser> _signin() async {
    setState(() {
      userPage = new Home(onSignin: null, onLogout: _logout, showLoading: true);
    });
    FirebaseAuth _auth = FirebaseAuth.instance;
    try {
      googleSignIn = new GoogleSignIn();
      GoogleSignInAccount googleSignInAccount = await googleSignIn.signIn();
      GoogleSignInAuthentication gauth =
          await googleSignInAccount.authentication;
      FirebaseUser user = await _auth.signInWithGoogle(
        accessToken: gauth.accessToken,
        idToken: gauth.idToken,
      );

      setState(() {
        _username = user.displayName;
        userPage = new User(
          onLogout: _logout,
          user: user,
        );
      });

      return user;
    } catch (e) {
      print(e.toString());
    }
    return null;
  }

  void _logout() async {
    await googleSignIn.signOut();
    setState(() {
      userPage = new Home(
        onSignin: () {
          _signin();
          print("Sign");
        },
        onLogout: _logout,
        showLoading: false,
      );
    });

    print("Logged Out");
  }

  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      home: userPage,
    );
  }
}

Special thanks to @nisrulz for this example.

Download Code