Firebase Social Authentication. Example in Kotlin.
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.
Firebase Welcome Message
Click on the Android option:Fill in your package details, click ‘Register App’:
Download Google Service JSON
Download the JSON file inside the ‘app’ folder of your project and click ‘Continue’:
Modify build.gradle file
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:
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:
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.
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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
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()
}
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:
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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()
}
}
}
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()
}
}
}
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:
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
private fun googleLogin(){
Log.i(TAG, "Starting Google LogIn Flow.")
val signInIntent = Auth.GoogleSignInApi.getSignInIntent(googleApiClient)
private fun googleLogin() {
Log.i(TAG, "Starting Google LogIn Flow.")
val signInIntent = Auth.GoogleSignInApi.getSignInIntent(googleApiClient)
startActivityForResult(signInIntent, GOOGLE_LOG_IN_RC)
}
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:
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
public override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent){
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()
}
}
}
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:
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
private fun firebaseAuthWithGoogle(acct: GoogleSignInAccount){
Log.i(TAG, "Authenticating user with firebase.")
val credential = GoogleAuthProvider.getCredential(acct.idToken, null)
// If sign in fails, display a message to the user.
Log.e(TAG, "Authenticating with Google credentials in firebase FAILED !!")
}
}
}
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 !!")
}
}
}
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:
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:
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
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:
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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
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)
}
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:
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:
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:
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
//Facebook Callback manager
var callbackManager: CallbackManager? = null
//Facebook Callback manager
var callbackManager: CallbackManager? = null
//Facebook Callback manager
var callbackManager: CallbackManager? = null
Now, initialise this callback and register it with Facebook login button we have in our app:
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:
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
public override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent){
public override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
super.onActivityResult(requestCode, resultCode, data)
callbackManager!!.onActivityResult(requestCode, resultCode, data)
...
}
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:
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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
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()
}
}
}
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:
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
https://apps.twitter.com/
https://apps.twitter.com/
https://apps.twitter.com/
Click on ‘Create New app option’:
Firebase. Login with Twitter Account.
Fill in the requested information and agree with terms if you do and click create.
Create new Twitter App
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:
Enter Twitter API Key and Secret Key into Firebase App
Remember to put the mentioned Callback URL in your Twitter app settings. Now, in the app’s build.gradle file, add the following:
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:
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()
}
}
}
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