Skip to content

Instantly share code, notes, and snippets.

@cogivn
Last active March 7, 2023 15:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cogivn/3a9567b2645666c4d2fbee0c8cdea09d to your computer and use it in GitHub Desktop.
Save cogivn/3a9567b2645666c4d2fbee0c8cdea09d to your computer and use it in GitHub Desktop.

Getting started

In your build.gradle:

dependencies {
  implementation 'co.legato.libraries:authentication:latest-version'
}

Maven Central

Supported

Social Authentication provides backend services, easy-to-use SDKs, and ready-made UI libraries to authenticate users to your app. It supports authentication using popular federated identity providers like:

  • Facebook Authentication
  • Google Authentication
  • Apple Authentication
  • Wechat Authentication
  • And more in the fututure as Github, Twitter, Microsoft, Yahoo, Play game sign in...

Usage

1. Copy authentication.xml file to res/values folder in app module at android project:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!-- Setup configuration for Facebook-->
    <string name="facebook_app_id" translatable="false">replace-with-your-id-here</string>
    <string name="fb_login_protocol_scheme" translatable="false">replace-with-your-id-here</string>
    <string name="facebook_client_token" translatable="false">replace-with-your-id-here</string>

    <!-- Setup configuration for Wechat-->
    <string name="wechat_app_id" translatable="false" >replace-with-your-id-here</string>
    <string name="wechat_secret_id" translatable="false" >replace-with-your-id-here</string>
    
     <!-- No need to configure setting [app_id] for apple and google login. It's already on the file `google-services.json`-->
</resources>

and then refill facebook_app_id, fb_login_protocol_scheme with your remote social app.

2. Setup on java/kotlin class:

class FirstFragment : Fragment(), SocialNetworkCallback {
   private val binding: FragmentFirstBinding by viewBinding(CreateMethod.INFLATE)
   private val manager = AuthenticationManager.getInstance()

   override fun onCreate(savedInstanceState: Bundle?) {
       super.onCreate(savedInstanceState)
       manager.apply {
           addNetwork(GoogleNetwork(requireActivity()))
           addNetwork(FacebookNetwork(requireActivity(), "email"))
           addNetwork(AppleNetwork(requireActivity()))
           addNetwork(WechatNetwork(requireActivity()))
       }
   }

   override fun onDestroy() {
       super.onDestroy()
       manager.reset()
   }

   override fun onCreateView(
       inflater: LayoutInflater, container: ViewGroup?,
       savedInstanceState: Bundle?
   ): View = binding.root

   override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
       super.onViewCreated(view, savedInstanceState)

       binding.apple.setOnClickListener {
           manager.get<AppleNetwork>(Network.APPLE).login(this)
       }
       binding.facebook.setOnClickListener {
           manager.get<FacebookNetwork>(Network.FACEBOOK).login(this)
       }
       binding.google.setOnClickListener {
           manager.get<GoogleNetwork>(Network.GOOGLE).login(this)
       }
       binding.wechat.setOnClickListener {
           manager.get<WechatNetwork>(Network.WECHAT).login(this)
       }
   }

   override fun onAuthenticationFailed(network: Network, throwable: Throwable?) {
       throwable?.printStackTrace()
   }

   override fun onAuthenticationSuccess(network: Network) {
       Toast.makeText(activity, "Authenticated", Toast.LENGTH_SHORT).show()
       val token = manager.get<ICoreNetwork>(network).getAccessToken()?.token
       Log.e("Authentication", "$network authenticated -> token = $token")
   }

   override fun onAuthenticationStart() = Unit
}

2.1 For WECHAT configuration then:

  • Generate signature key: Gradle -> Task -> android -> signingReport. Copy MD5 encoded string, remove colon character and add them in your Wechat Console: md5-signature-key
  • Create a new directory under your package name wxapi Directory and in the wxapi Add a new one to the directory WXEntryActivity Class, which inherits from the Activity such as the package name of the application. new-activity-class

WXEntryActivity should be extended from HandlingEventActivity to catch data from wechat sdk

import vn.cogi.authentication.wxapi.HandlingEventActivity

class WXEntryActivity : HandlingEventActivity()

And in manifest Add the export, taskAffinity, and launchMode attributes to the file, where export is set to true, tasksAfficity to your package name, and launch Mode to singleTask, for example:

<activity
    android:name=".wxapi.WXEntryActivity"
    android:label="@string/app_name"
    android:theme="@android:style/Theme.Translucent.NoTitleBar"
    android:exported="true"
    Android: taskAffinity = "fill in your bag name"
    android:launchMode="singleTask">
</activity>

3. Link Multiple Auth Providers to an Account

We goto Firebase Console --> Authentication -> Settings and tick into Link account that use the same email: enable-link-provider-account

By default, if FirebaseAuth.getInstance().currentUser is available. The Authentication library automatically associates the target provider with the account. In the case of FirebaseAuth.getInstance().currentUser returns null, the user hasn't been authenticated before, so we have to login with the provider associated with that email address first. Then start linking the target provider to an account. The full sample will be described below:

/**
 * A simple [Fragment] subclass as the default destination in the navigation.
 */
class FirstFragment : Fragment(), SocialNetworkCallback {
   private val manager = AuthenticationManager.getInstance()


    ....

    override fun onAuthenticationFailed(network: Network, throwable: Throwable?) {
        if (throwable is FirebaseAuthUserCollisionException) {
            handleFirebaseAuthUserCollisionException(network, throwable)
        }
        throwable?.printStackTrace()
    }

    @Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE")
    private fun handleFirebaseAuthUserCollisionException(
        network: Network, throwable: FirebaseAuthUserCollisionException
    ) {
        val credential = throwable.updatedCredential ?: return
        val callback = object : SocialNetworkCallback {
            override fun onAuthenticationStart() = Unit
            override fun onAuthenticationFailed(network: Network, throwable: Throwable?) = Unit
            override fun onAuthenticationSuccess(localNetwork: Network) {
                Log.e("Authentication", "Target network: $network, Local $localNetwork success")
                manager.get<ICoreNetwork>(network).linkWithCredential(credential)
            }
        }
        manager.fetchSignInMethodsForEmail(throwable.email) { providers ->
            if (GoogleAuthProvider.PROVIDER_ID in providers) {
                // start re-authentication with google provider
                manager.get<ICoreNetwork>(Network.GOOGLE).login(callback)
            }
        }
        Log.e("Authentication", "$network failed")
    }

    override fun onAuthenticationSuccess(network: Network) {
        Toast.makeText(activity, "Authenticated", Toast.LENGTH_SHORT).show()
        val token = manager.get<ICoreNetwork>(network).getAccessToken()?.token
        Log.e("Authentication", "$network authenticated -> token = $token")
    }

    override fun onAuthenticationStart() = Unit
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment