Kotlin Firebase Authentication – Google Sign In | Android

In previous post, we had built a simple register/login Android App using Firebase Email & Password authentication. Now we can let users authenticate with Firebase using Google Accounts by integrating Google Sign In into Kotin Android App.

Related articles:
Kotlin Firebase Authentication – How to Sign Up, Sign In, Sign Out, Verify Email | Android
Kotlin Firebase Authentication – Send Reset Password Email / Forgot Password | Android

I. Way to do

1. Add Firebase to Android App

– Read Kotlin Firebase Authentication – How to Sign Up, Sign In, Sign Out, Verify Email | Android and follow steps to enable and implement Firebase Auth in your Android App.

– Add dependency: build.gradle (App-level):


dependencies {
    // ...
    implementation 'com.google.android.gms:play-services-auth:11.0.4'
}

2. Enable Firebase Auth for Google Account

Go to Your Firebase Project Console -> Authentication -> SIGN-IN METHOD -> Enable Google:
firebase-google-signin-enable-console

3. Steps to authenticate with Firebase

3.1 Integrate Google Sign In into App

1- Add the Google Sign-In button:



2- Configure Google Sign In object to request the user data:
When you configure the GoogleSignInOptions object, call requestIdToken:


override fun onCreate(savedInstanceState: Bundle?) {
    // ...

    val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
            .requestIdToken(WEB_CLIENT_ID)
            .requestEmail()
            .build()
}

With WEB_CLIENT_ID from Credentials page in the API Console -> OAuth 2.0 client IDs (Type Web Application).

3- Configure GoogleApiClient object with access to the Google Sign In API and the options above:


private var mGoogleApiClient: GoogleApiClient? = null

override fun onCreate(savedInstanceState: Bundle?) {
    // ...

    mGoogleApiClient = GoogleApiClient.Builder(this)
            .enableAutoManage(this /* FragmentActivity */, this /* OnConnectionFailedListener */)
            .addApi(Auth.GOOGLE_SIGN_IN_API, gso)
            .build()
}

3.2 signIn() method


private fun signIn() {
    val intent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient)
    startActivityForResult(intent, REQUEST_CODE_SIGN_IN)
}

In the activity’s onActivityResult() method, we retrieve the sign-in result with Auth.GoogleSignInApi.getSignInResultFromIntent():


override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    // Result returned from launching the Intent from GoogleSignInApi.getSignInIntent();
    if (requestCode == REQUEST_CODE_SIGN_IN) {
        val result = Auth.GoogleSignInApi.getSignInResultFromIntent(data)
        if (result.isSuccess) {
            // successful -> authenticate with Firebase
            val account = result.signInAccount
            firebaseAuthWithGoogle(account!!)
        } else {
            // failed -> update UI
            updateUI(null)
        }
    }
}

3.3 Initialize the FirebaseAuth instance

In the Activity onCreate() method:


private var mAuth: FirebaseAuth? = null

override fun onCreate(savedInstanceState: Bundle?) {
    // ...
    mAuth = FirebaseAuth.getInstance()
}

3.4 Check if the user is currently signed in

In Activity onStart() method:


override fun onStart() {
    super.onStart()
    // Check if user is signed in (non-null) and update UI accordingly.
    val currentUser = mAuth!!.currentUser
    updateUI(currentUser)
}

3.5 Authenticate with Firebase using the Firebase credential

For firebaseAuthWithGoogle() method above:
After a user successfully signs in (in onActivityResult), get an ID token from the GoogleSignInAccount object, exchange it for a Firebase credential, then authenticate with Firebase using the Firebase credential:


private fun firebaseAuthWithGoogle(acct: GoogleSignInAccount) {
    Log.e(TAG, "firebaseAuthWithGoogle():" + acct.id!!)
    val credential = GoogleAuthProvider.getCredential(acct.idToken, null)
    mAuth!!.signInWithCredential(credential)
            .addOnCompleteListener(this) { task ->
                if (task.isSuccessful) {
                    // Sign in success
                    val user = mAuth!!.currentUser
                    updateUI(user)
                } else {
                    // Sign in fails
                    updateUI(null)
                }
            }
}

4. Sign Out User and Disconnect Account

4.1 Sign out User


private fun signOut() {
    // sign out Firebase
    mAuth!!.signOut()
    // sign out Google
    Auth.GoogleSignInApi.signOut(mGoogleApiClient).setResultCallback { updateUI(null) }
}

4.2 Disconnect Account


private fun revokeAccess() {
    // sign out Firebase
    mAuth!!.signOut()
    // revoke access Google
    Auth.GoogleSignInApi.revokeAccess(mGoogleApiClient).setResultCallback { updateUI(null) }
}

II. Practice

1. Goal

We will build an Android App that can sign in/sign out, disconnect Google Account:

kotlin-firebase-google-signin-app-demo

2. Technology

– Gradle 3.0.1
– Android Studio 3.x
– Firebase Android SDK 11.x

3. Project Structure

kotlin-firebase-google-signin-structure

4. Step by step

4.1 Create Android Project & add Firebase Auth

– Generate new Android Project with package com.javasampleapproach.kotlin.authgoogle.
– Follow these steps to add Firebase to Android Project.
– Don’t forget to enable Firebase Auth for Google Account:
firebase-google-signin-enable-console

– Add dependency: build.gradle (App-level):


dependencies {
    // ...
    implementation 'com.google.android.gms:play-services-auth:11.0.4'
}

4.2 Get server’s client ID

To find the OAuth 2.0 client ID:
– Open the Credentials page in the API Console.
– Select your Firebase Project.
– Scroll down to OAuth 2.0 client IDs, copy Client ID (Web Application Type).

4.3 Activity

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/main_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#F5F5F5"
    android:orientation="vertical"
    android:weightSum="3">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="2"
        android:gravity="center_horizontal"
        android:orientation="vertical">

        <TextView
            android:id="@+id/title_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginBottom="20dp"
            android:gravity="center"
            android:text="grokonez.com Google Sign In"
            android:textSize="30sp" />

        <TextView
            android:id="@+id/tvStatus"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:padding="4sp"
            android:text="Signed Out"
            android:textSize="18sp" />

        <TextView
            android:id="@+id/tvDetail"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:padding="4sp"
            android:textSize="18sp"
            tools:text="Firebase User ID: 123456789abc" />

    </LinearLayout>


    <RelativeLayout
        android:layout_width="fill_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:background="#E0E0E0">

        <com.google.android.gms.common.SignInButton
            android:id="@+id/btn_sign_in"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:visibility="visible"
            tools:visibility="gone" />

        <LinearLayout
            android:id="@+id/layout_sign_out_and_disconnect"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:orientation="horizontal"
            android:paddingLeft="16dp"
            android:paddingRight="16dp"
            android:visibility="gone"
            tools:visibility="visible">

            <Button
                android:id="@+id/btn_sign_out"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_marginLeft="4dp"
                android:layout_marginRight="4dp"
                android:layout_weight="1"
                android:text="Sign Out" />

            <Button
                android:id="@+id/btn_disconnect"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_marginLeft="4dp"
                android:layout_marginRight="4dp"
                android:layout_weight="1"
                android:text="Disconnect" />
        </LinearLayout>

    </RelativeLayout>

</LinearLayout>

package com.javasampleapproach.kotlin.authgoogle

import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.Toast
import kotlinx.android.synthetic.main.activity_google_signin.*
import com.google.android.gms.auth.api.Auth
import com.google.android.gms.common.api.GoogleApiClient
import com.google.firebase.auth.FirebaseAuth
import com.google.android.gms.auth.api.signin.GoogleSignInOptions
import com.google.android.gms.common.ConnectionResult
import com.google.firebase.auth.FirebaseUser
import android.content.Intent
import com.google.android.gms.auth.api.signin.GoogleSignInAccount
import com.google.firebase.auth.GoogleAuthProvider

class GoogleSigninActivity : AppCompatActivity(), View.OnClickListener, GoogleApiClient.OnConnectionFailedListener {

    private val TAG = "JSAGoogleSignIn"
    private val REQUEST_CODE_SIGN_IN = 1234
    private val WEB_CLIENT_ID = "xxxxxx.apps.googleusercontent.com"

    private var mAuth: FirebaseAuth? = null

    private var mGoogleApiClient: GoogleApiClient? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_google_signin)

        btn_sign_in.setOnClickListener(this)
        btn_sign_out.setOnClickListener(this)
        btn_disconnect.setOnClickListener(this)

        val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
                .requestIdToken(WEB_CLIENT_ID)
                .requestEmail()
                .build()

        mGoogleApiClient = GoogleApiClient.Builder(this)
                .enableAutoManage(this /* FragmentActivity */, this /* OnConnectionFailedListener */)
                .addApi(Auth.GOOGLE_SIGN_IN_API, gso)
                .build()

        mAuth = FirebaseAuth.getInstance()
    }

    override fun onStart() {
        super.onStart()

        // Check if user is signed in (non-null) and update UI accordingly.
        val currentUser = mAuth!!.currentUser
        updateUI(currentUser)
    }

    override fun onClick(v: View?) {
        val i = v!!.id

        when (i) {
            R.id.btn_sign_in -> signIn()
            R.id.btn_sign_out -> signOut()
            R.id.btn_disconnect -> revokeAccess()
        }
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)

        // Result returned from launching the Intent from GoogleSignInApi.getSignInIntent();
        if (requestCode == REQUEST_CODE_SIGN_IN) {
            val result = Auth.GoogleSignInApi.getSignInResultFromIntent(data)
            if (result.isSuccess) {
                // successful -> authenticate with Firebase
                val account = result.signInAccount
                firebaseAuthWithGoogle(account!!)
            } else {
                // failed -> update UI
                updateUI(null)
                Toast.makeText(applicationContext, "SignIn: failed!",
                        Toast.LENGTH_SHORT).show()
            }
        }
    }

    private fun firebaseAuthWithGoogle(acct: GoogleSignInAccount) {
        Log.e(TAG, "firebaseAuthWithGoogle():" + acct.id!!)

        val credential = GoogleAuthProvider.getCredential(acct.idToken, null)
        mAuth!!.signInWithCredential(credential)
                .addOnCompleteListener(this) { task ->
                    if (task.isSuccessful) {
                        // Sign in success
                        Log.e(TAG, "signInWithCredential: Success!")
                        val user = mAuth!!.currentUser
                        updateUI(user)
                    } else {
                        // Sign in fails
                        Log.w(TAG, "signInWithCredential: Failed!", task.exception)
                        Toast.makeText(applicationContext, "Authentication failed!",
                                Toast.LENGTH_SHORT).show()
                        updateUI(null)
                    }
                }
    }

    override fun onConnectionFailed(connectionResult: ConnectionResult) {
        Log.e(TAG, "onConnectionFailed():" + connectionResult);
        Toast.makeText(applicationContext, "Google Play Services error.", Toast.LENGTH_SHORT).show();
    }

    private fun signIn() {
        val intent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient)
        startActivityForResult(intent, REQUEST_CODE_SIGN_IN)
    }

    private fun signOut() {
        // sign out Firebase
        mAuth!!.signOut()

        // sign out Google
        Auth.GoogleSignInApi.signOut(mGoogleApiClient).setResultCallback { updateUI(null) }
    }

    private fun revokeAccess() {
        // sign out Firebase
        mAuth!!.signOut()

        // revoke access Google
        Auth.GoogleSignInApi.revokeAccess(mGoogleApiClient).setResultCallback { updateUI(null) }
    }

    private fun updateUI(user: FirebaseUser?) {
        if (user != null) {
            tvStatus.text = "Google User email: " + user.email!!
            tvDetail.text = "Firebase User ID: " + user.uid

            btn_sign_in.visibility = View.GONE
            layout_sign_out_and_disconnect.visibility = View.VISIBLE
        } else {
            tvStatus.text = "Signed Out"
            tvDetail.text = null

            btn_sign_in.visibility = View.VISIBLE
            layout_sign_out_and_disconnect.visibility = View.GONE
        }
    }
}

WEB_CLIENT_ID is the Client ID we get in the previous step.

4.4 Run & Check result

– Use Android Studio, build and Run your Android App.

firebase-google-signin-app-demo

– Firebase Console:
kotlin-firebase-google-signin-app-console

III. Source code

Koltin-Auth-Google-SignIn



By grokonez | December 16, 2017.

Last updated on April 24, 2021.



Related Posts


6 thoughts on “Kotlin Firebase Authentication – Google Sign In | Android”

  1. Thanks for the great example.

    I am getting an error when using an emulator (pixel 2 27):
    W/GooglePlayServicesUtil: Google Play services out of date. Requires 11910000 but found 11580470

    Play services are installed on emulator and every seem to be up to date on Android Studio. Any ideas on what to try?

    1. Hi Stephen Thoms,

      It looks like you are trying to run using an API 27 emulator image.

      Your options are to run using an API 26 emulator image, or downgrade the library versions in your build:

      compileSdkVersion 26
      ...
      targetSdkVersion 26
      ...
      // for all Support Libs, use 26.1.0
      ...
      

      Regards,
      JSA.

Got Something To Say:

Your email address will not be published. Required fields are marked *

*