In this tutorial on Firebase and Kotlin, we will learn how to use Firebase Social Authentication API to implement User Registration feature and store user data in Firebase and then allow user to login into our mobile app using their social accounts for either Google, Twitter or Facebook. We will also learn how to fetch some user specific information from the above mentioned social platforms. Firebase provides us with many Cloud Services which we can use to speed up our development process and implement relatively time consuming features much faster. For example in this and in following up tutorial I will use:
- Social Authentication API
- Real Time Database
- Cloud Storage
- Analytics
- Notification Services
Let’s begin with Social Authentication with Firebase. And first of all we will need to create a new Firebase App.
Create a new project in Firebase
To use Firebase with your mobile application you will need to have a project created in Firebase. You can create a new project using Firebase console and name it ‘FirebaseSocialAuth’. Once you click on ‘Create project’ button, we’re done with the initial process. You will see a Welcome message from Firebase like the one below.
Click on the Android option: Fill in your package details, click ‘Register App’:
Download the JSON file inside the ‘app’ folder of your project and click ‘Continue’:
Do the changes in gradle file as mentioned and click ‘Finish’. Once this is done, sync gradle file and wait for it to finish. Once everything is done, you’ll see the Android app appear in Firebase console as:
Adding Dependencies
Now, to enable social authentication, we need to add some Firebase dependencies manually. We will add Facebook and Google LogIn dependencies as:
//For Google SignIn compile 'com.google.firebase:firebase-auth:11.4.2' compile 'com.google.android.gms:play-services-auth:11.4.2' //Facebook SignIn compile 'com.facebook.android:facebook-login:[4,5)'
Make sure that, you have ‘Google Play Services’ installed. You can check that it is by going to Android Studio Preferences as shown on the picture below: Move to Appearance & Behaviour > System Settings > Android SDK and click on SDK Tools tab: This service is required so that Firebase SignIn works in the Google Emulator as well.
Making a simple UI
In our sample application, we will make a simple UI with:
- Three buttons, each for login via Google, Facebook and Twitter in CreateAccount activity.
- Once we login through a platform, we will show some platform specific data in our MainActivity.
Our CreateAccount activity will have three buttons and will look like this: Following is the XML for this interface:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_margin="20dp"> <com.google.android.gms.common.SignInButton android:id="@+id/google_sign_in_button" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="15dp" /> <com.facebook.login.widget.LoginButton android:id="@+id/facebook_sign_in_button" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_below="@id/google_sign_in_button" android:layout_marginBottom="15dp" /> <com.twitter.sdk.android.core.identity.TwitterLoginButton android:id="@+id/twitter_sign_in_button" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/facebook_sign_in_button" /> </RelativeLayout>
As you can see, Google, Facebook and Twitter actually provide a custom button for SignIn. Let’s now make these buttons work.
Firebase Social Authentication. Sign in with Google Account.
Let’s start by working on Google SignIn. In Firebase console, visit the ‘Authentication’ tab, enable Google SignIn and you will see this: Expand the Web SDK configuration section and copy the value of Web client ID and click on Save button.
Then, add the value of Web client ID you have copied into strings.xml file as request_client_id. This will enable Google SignIn for your app. Now that we’re done with a basic UI, we will start integrating Google SignIn in the app.
val TAG = "CreateAccount" //Init views lateinit var googleSignInButton: SignInButton lateinit var facebookSignInButton: LoginButton lateinit var twitterSignInButton: TwitterLoginButton //Request codes val GOOGLE_LOG_IN_RC = 1 val FACEBOOK_LOG_IN_RC = 2 val TWITTER_LOG_IN_RC = 3 // Google API Client object. var googleApiClient: GoogleApiClient? = null // Firebase Auth Object. var firebaseAuth: FirebaseAuth? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_create_account) googleSignInButton = findViewById<View>(R.id.google_sign_in_button) as SignInButton facebookSignInButton = findViewById<View>(R.id.facebook_sign_in_button) as LoginButton twitterSignInButton = findViewById<View>(R.id.twitter_sign_in_button) as TwitterLoginButton googleSignInButton.setOnClickListener(this@CreateAccount) firebaseAuth = FirebaseAuth.getInstance() // Configure Google Sign In val googleSignInOptions = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) .requestIdToken(getString(R.string.request_client_id)) .requestEmail() .build() // Creating and Configuring Google Api Client. googleApiClient = GoogleApiClient.Builder(this@CreateAccount) .enableAutoManage(this@CreateAccount /* OnConnectionFailedListener */) { } .addApi(Auth.GOOGLE_SIGN_IN_API, googleSignInOptions) .build() }
Above, we just defined and initialised our View references, along with Firebase Authentication. We will also initialise Google Login options which prepare Google LogIn process, but doesn’t launch it. We handle the button clicks in their following methods:
override fun onClick(view: View?) { when (view?.id) { R.id.google_sign_in_button -> { Log.i(TAG, "Trying Google LogIn.") googleLogin() } R.id.twitter_sign_in_button -> { Log.i(TAG, "Trying Twitter LogIn.") twitterLogin() } } }
Now, we will define the googleLogin method:
private fun googleLogin() { Log.i(TAG, "Starting Google LogIn Flow.") val signInIntent = Auth.GoogleSignInApi.getSignInIntent(googleApiClient) startActivityForResult(signInIntent, GOOGLE_LOG_IN_RC) }
This intent starts GoogleSignInApi flow. This ensures that when the login button for Google is clicked, the dialog with user’s Google account is presented. If there are more than one Google account on device, the user is invited to chose one account with which they would like to sign in. When an account is selected, Google return the control to our app in onActivityResult method:
public override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) { super.onActivityResult(requestCode, resultCode, data) Log.i(TAG, "Got Result code ${requestCode}.") // Result returned from launching the Intent from GoogleSignInApi.getSignInIntent(...); if (requestCode == GOOGLE_LOG_IN_RC) { val result = Auth.GoogleSignInApi.getSignInResultFromIntent(data) Log.i(TAG, "With Google LogIn, is result a success? ${result.isSuccess}.") if (result.isSuccess) { // Google Sign In was successful, authenticate with Firebase firebaseAuthWithGoogle(result.signInAccount!!) } else { Toast.makeText(this@CreateAccount, "Some error occurred.", Toast.LENGTH_SHORT).show() } } }
Once the Google SignIn has succeeded, we will use same credentials to login to the Firebase, defining firebaseAuthWithGoogle method as:
private fun firebaseAuthWithGoogle(acct: GoogleSignInAccount) { Log.i(TAG, "Authenticating user with firebase.") val credential = GoogleAuthProvider.getCredential(acct.idToken, null) firebaseAuth?.signInWithCredential(credential)?.addOnCompleteListener(this) { task -> Log.i(TAG, "Firebase Authentication, is result a success? ${task.isSuccessful}.") if (task.isSuccessful) { // Sign in success, update UI with the signed-in user's information startActivity(Intent(this@CreateAccount, MainActivity::class.java)) } else { // If sign in fails, display a message to the user. Log.e(TAG, "Authenticating with Google credentials in firebase FAILED !!") } } }
Getting User Information
Once we have Logged in, we will need to show a new Activity with some user information on it. We will define a new activity named as MainActivity. Currently, its UI is defined as: Its XML is defined as:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout ...> <ImageView android:id="@+id/iv_profile" android:layout_width="200dp" android:layout_height="200dp" android:layout_centerHorizontal="true" android:src="@drawable/defaultphoto" /> <TextView android:id="@+id/tv_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/iv_profile" android:layout_centerHorizontal="true" android:text="Name" android:textSize="18sp" /> <TextView android:id="@+id/tv_email" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/tv_name" android:layout_centerHorizontal="true" android:text="Email" android:textSize="18sp" /> <TextView android:id="@+id/tv_id" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/tv_email" android:layout_centerHorizontal="true" android:text="User ID" android:textSize="18sp" /> </RelativeLayout>
We have also added an ImageView in which we will show a user’s profile image if received from the social platform in use. To show image, we will use Picasso. Add its gradle dependency to use it:
//To load image implementation 'com.squareup.picasso:picasso:2.5.2'
Define the references to the View elements as:
val TAG = "MainActivity" // Firebase Auth Object. var firebaseAuth: FirebaseAuth? = null lateinit var ivProfilePicture: ImageView lateinit var tvName: TextView lateinit var tvEmail: TextView lateinit var tvUserId: TextView
Finally, in onCreate method of MainActivity, we will fetch current user from Firebase and extract available information from it:
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) firebaseAuth = FirebaseAuth.getInstance() ivProfilePicture = findViewById<View>(R.id.iv_profile) as ImageView tvName = findViewById<View>(R.id.tv_name) as TextView tvEmail = findViewById<View>(R.id.tv_email) as TextView tvUserId = findViewById<View>(R.id.tv_id)as TextView val user = firebaseAuth?.currentUser Log.i(TAG, "User account ID ${user?.uid}") Log.i(TAG, "Display Name : ${user?.displayName}") Log.i(TAG, "Email : ${user?.email}") Log.i(TAG, "Photo URL : ${user?.photoUrl}") Log.i(TAG, "Provider ID : ${user?.providerId}") tvName.text = user?.displayName tvEmail.text = user?.email tvUserId.text = user?.uid Picasso.with(this@MainActivity) .load(user?.photoUrl) .into(ivProfilePicture) }
This code snippet will fetch user information and show it in the View.
Sign in with Facebook account
We can use Firebase Social Authentication to implement the Facebook Sign In as well and we will define the same MainActivity to show information fetched from Facebook and Twitter To enable Facebook Login to the app, we will first need to visit Facebook Developer’s page and get following information:
- Facebook App ID
- Facebook App Secret
When you open Facebook developers page using the above link, you should see the following option: Create a new app. I named it ‘FirebaseSocialAuth’. Open the app page and you’ll see following information:
Now, move to the Firebase Console and under ‘Authentication’ tab once again, enable Firebase Login for Facebook and enter this information:
Also add Facebook App ID and Facebook App secret to strings.xml file:
<string name="facebook_app_id">30…………51</string> <string name="fb_login_protocol_scheme">a31e…………18</string>
Next, add following tags inside the Manifest xml file:
<meta-data android:name="com.facebook.sdk.ApplicationId" android:value="@string/facebook_app_id"/> <activity android:name="com.facebook.FacebookActivity" android:configChanges="keyboard|keyboardHidden|screenLayout|screenSize|orientation" android:label="@string/app_name" /> <activity android:name="com.facebook.CustomTabActivity" android:exported="true"> <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:scheme="@string/fb_login_protocol_scheme" /> </intent-filter> </activity>
We wil need to complete all the steps mentioned on the page which you can open by going to the URL below:
https://developers.facebook.com/apps/<your-app-id>/fb-login/quickstart/
I will also demonstrate the steps here for clarifications.
Generate a Hash code
To ensure the authenticity of the interactions between your app and Facebook, we need to supply Facebook with the Android key hash for our development environment. If the app has already been published, we should add the release key hash too. Key hash can be generated on mac as:
keytool -exportcert -alias androiddebugkey -keystore ~/.android/debug.keystore | openssl sha1 -binary | openssl base64
On Windows, we can run this command:
keytool -exportcert -alias androiddebugkey -keystore %HOMEPATH%\.android\debug.keystore | openssl sha1 -binary | openssl base64
Once this is done, in the CreateAccount activity, initialise the Facebook SDK as:
FacebookSdk.sdkInitialize(getApplicationContext()) AppEventsLogger.activateApp(this@CreateAccount)
Tell Facebook Your Package Name
When Facebook launches its activity from our app, it needs to know the context of the Activity from which it will be opening. We will need to profile Facebook App with our package name and Activity information:
Now, turn on SSO (Single Sign in On): Now, in your activity, define Facebook’s callback so that facebook can return results when a user logs in:
//Facebook Callback manager var callbackManager: CallbackManager? = null
Now, initialise this callback and register it with Facebook login button we have in our app:
callbackManager = CallbackManager.Factory.create(); facebookSignInButton.setReadPermissions("email") // Callback registration facebookSignInButton.registerCallback(callbackManager, object : FacebookCallback<LoginResult> { override fun onSuccess(loginResult: LoginResult) { // App code handleFacebookAccessToken(loginResult.accessToken); } override fun onCancel() { // App code } override fun onError(exception: FacebookException) { // App code } })
Finally, add this callback in onActivityResult method as well so that when control is returned to our app, we can get result from Facebook SDK based on user process:
public override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) { super.onActivityResult(requestCode, resultCode, data) callbackManager!!.onActivityResult(requestCode, resultCode, data) ... }
We finally define our handleFacebookAccessToken methow which will handle the result received via Callback and move to next Activity if sign in was a success:
private fun handleFacebookAccessToken(token: AccessToken) { Log.d(TAG, "handleFacebookAccessToken:" + token) val credential = FacebookAuthProvider.getCredential(token.token) firebaseAuth!!.signInWithCredential(credential) .addOnCompleteListener(this) { task -> if (task.isSuccessful) { // Sign in success, update UI with the signed-in user's information Log.d(TAG, "signInWithCredential:success") val user = firebaseAuth!!.currentUser startActivity(Intent(this@CreateAccount, MainActivity::class.java)) } else { // If sign in fails, display a message to the user. Log.w(TAG, "signInWithCredential:failure", task.getException()) Toast.makeText(this@CreateAccount, "Authentication failed.", Toast.LENGTH_SHORT).show() } } }
Now, the app is again ready to run. We will see similar results as we saw in Google Login option.
Firebase Social Authentication. Login with Twitter Account.
Finally, we will add Twitter login into our app. To start, we need Twitter API key and API secret which can be obtained from following URL:
https://apps.twitter.com/
Click on ‘Create New app option’:
Fill in the requested information and agree with terms if you do and click create.
Once you confirm, you will following information: On the available tabs, click on ‘Keys and Access Tokens’ where you get both values: Finally, in the Firebase console, enable Twitter Sign in and enter both of these values:
Remember to put the mentioned Callback URL in your Twitter app settings. Now, in the app’s build.gradle file, add the following:
//Inside android section repositories { jcenter() } dependencies { ... compile('com.twitter.sdk.android:twitter:3.1.1@aar') { transitive = true } ... }
Once that is done, we can define the TwitterLoginButton in our UI and in our activity as well. Just what we did with Facebook, add a callback for Twitter LoginButton as well:
twitterSignInButton.callback = object : Callback<TwitterSession>() { override fun success(result: Result<TwitterSession>) { Log.d(TAG, "twitterLogin:success" + result) handleTwitterSession(result.data) } override fun failure(exception: TwitterException) { Log.w(TAG, "twitterLogin:failure", exception) } }
In our handleTwitterSession method, we will handle result obtained form Twitter SDK:
private fun handleTwitterSession(session: TwitterSession) { Log.d(TAG, "handleTwitterSession:" + session) val credential = TwitterAuthProvider.getCredential( session.authToken.token, session.authToken.secret) firebaseAuth!!.signInWithCredential(credential) .addOnCompleteListener(this) { task -> if (task.isSuccessful) { // Sign in success, update UI with the signed-in user's information Log.d(TAG, "signInWithCredential:success") val user = firebaseAuth!!.currentUser startActivity(Intent(this@CreateAccount, MainActivity::class.java)) } else { // If sign in fails, display a message to the user. Log.w(TAG, "signInWithCredential:failure", task.getException()) Toast.makeText(this@CreateAccount, "Authentication failed.", Toast.LENGTH_SHORT).show() } } }
Excellent, once that is done, it’s time to run your app again. You will see similar information on the MainActivity page. Note that some information for User maybe missing, depending on the social platform policy for user information usage. I hope this programming tutorial on Kotlin and Firebase Social Authentication was of good value to you. Play with this code to make your dream app! Firebase is very powerful and easy to learn cloud platform. I encourage you to learn more about it and to check the below books and video lessons that will help you get most out of Firebase and build professional mobile apps powered by Google Cloud.
Building Mobile Apps with Kotlin and Firebase – Books
Building Mobile Apps with Kotlin and Firebase – Video Courses