prevent google credentials save in android - android

I am using Firebase Google Authentication services. Authentication is working fine, But the problem is that when I sign In with google auth, credentials get saved. So after every logout, I can not be able to choose an email for login. It directly login me into the app. So it becomes a problem for me when I want to login with another Gmail account.
Code to achieve the credentials page.
google_sign_in_btn.setOnClickListener {
signIn()
}
...
private fun signIn() {
val signInIntent = mGoogleSignInClient.signInIntent
startActivityForResult(signInIntent, 234)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == 234)
{
val task = GoogleSignIn.getSignedInAccountFromIntent(data)
try
{
val account = task.getResult(ApiException::class.java)
if (account != null) {
firebaseAuthWithGoogle(account)
}
}
catch (e:ApiException) {
}
}
}

The problem that you are facing is that you don't sign out the user from the Google provider. It's not enough to sign out only from Firebase. If you want to get that pop-up every time, so you can choose the email account you want to use, sign out from both Google and Firebase:
googleSignInClient.signOut().addOnCompleteListener { /* ... /* }
FirebaseAuth.getInstance().signOut()

Related

do I need to use try and catch in Firebase authentication codes in Kotlin - Android

Do I need to use try and catch in Firebase authentication codes in Kotlin? i.e. in here or similar places you know as experts the goal is to prevent the crashes:
fun handleFirebaseAuthWithGoogle(idToken: String) {
val credential = GoogleAuthProvider.getCredential(idToken, null)
FirebaseAuthRepository().auth.signInWithCredential(credential)
.addOnCompleteListener { task ->
if (task.isSuccessful) {
_isNewUser.value = task.result.additionalUserInfo?.isNewUser
// Sign in success, update UI with the signed-in user's information
Log.d(LoginFragment.TAG, "signInWithCredential:success")
FirebaseAuthRepository().getCurrentUser {
_authWithGoogle.value = it
}
} else {
// If sign in fails, display a message to the user.
Log.w(LoginFragment.TAG, "signInWithCredential:failure", task.exception)
}
}
}
also here:
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 == RC_SIGN_IN) {
val task = GoogleSignIn.getSignedInAccountFromIntent(data)
try {
// Google Sign In was successful, authenticate with Firebase
val account = task.getResult(ApiException::class.java)!!
Log.d(TAG, "firebaseAuthWithGoogle:" + account.id)
viewModel.handleFirebaseAuthWithGoogle(account.idToken!!)
UiUtils.showSnackBar(requireView(), "Google sign in Succeed", 0)
} catch (e: ApiException) {
// Google Sign In failed, update UI appropriately
Log.w(TAG, "Google sign in failed", e)
hideProgress()
UiUtils.showErrorSnackBar(requireView(), "Google sign in failed", 0)
}
}
}
When you are attempting to implement an authentication mechanism, there are multiple operations that can go wrong. In such cases, we always need to handle the Exceptions.
In your second snippet code, it makes sense to use a try-catch to handle the ApiException, while in the first it doesn't. When you deal with Firebase services, you can get a successful operation or an Exception, never both. It's one or the other. So if the task is successful, then you are successfully authenticated, otherwise, you get an Exception. You can get the corresponding Exception by calling getException() method on the Task object. So there is no need to use a try-catch here because your app won't crash in case of an Exception.
You can use .addOnSuccessListener and .addOnFailureListener to handle the different FirebaseExceptions which can be thrown while authentication.

How to implement google sign in

I implemented the google sign in api in my android app. Everything was fine until recently. One of the challenges I had was with client_id which regenerated. The most recent that has opened more errors is that the google sign in wont work in the release.apk that built.
After two days of debugging I decided to create a new demo project to start the process afresh. It won't work as the task return false for task.isSuccessful.
Perhaps there is something I am missing.
const val RC_SIGN_IN = 0
class MainActivity : AppCompatActivity() {
lateinit var observer:StartActivityForResults
private lateinit var mGoogleSignInClient:GoogleSignInClient
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
observer = StartActivityForResults(activityResultRegistry)
lifecycle.addObserver(observer)
val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestEmail()
.build()
mGoogleSignInClient = GoogleSignIn.getClient(this, gso);
sign_in_button.setOnClickListener{
signIn()
}
}
private fun signIn() {
val signInIntent = mGoogleSignInClient.signInIntent
startActivityForResult(signInIntent, RC_SIGN_IN)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
// Result returned from launching the Intent from GoogleSignInClient.getSignInIntent(...);
if (requestCode == RC_SIGN_IN) {
// The Task returned from this call is always completed, no need to attach
// a listener.
val task = Auth.GoogleSignInApi.getSignInResultFromIntent(data)
task?.isSuccess
Toast.makeText(this, "Success", Toast.LENGTH_LONG).show()
}
else{
Log.i("title", "OKCODE ${Activity.RESULT_OK} RESULTCODE ${resultCode}")
}
}
}
Easily add sign-in to your Android app with FirebaseUI
If you haven't already, add Firebase to your Android project.
Add the dependencies for FirebaseUI to your app-level build.gradle file
dependencies {
// ...
implementation 'com.firebaseui:firebase-ui-auth:6.2.0'
}
In the Firebase console, open the Authentication section and enable the sign-in methods you want to support. Some sign-in methods require additional information, usually available in the service's developer console.
If you support Google Sign-in and haven't yet specified your app's SHA-1 fingerprint, do so from the Settings page of the Firebase console
// Choose authentication providers
val providers = arrayListOf(
AuthUI.IdpConfig.EmailBuilder().build(),
AuthUI.IdpConfig.PhoneBuilder().build(),
AuthUI.IdpConfig.GoogleBuilder().build(),
AuthUI.IdpConfig.FacebookBuilder().build(),
AuthUI.IdpConfig.TwitterBuilder().build())
// Create and launch sign-in intent
startActivityForResult(
AuthUI.getInstance()
.createSignInIntentBuilder()
.setAvailableProviders(providers)
.build(),
RC_SIGN_IN)
When the sign-in flow is complete, you will receive the result in onActivityResult:
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == RC_SIGN_IN) {
val response = IdpResponse.fromResultIntent(data)
if (resultCode == Activity.RESULT_OK) {
// Successfully signed in
val user = FirebaseAuth.getInstance().currentUser
// ...
} else {
// Sign in failed. If response is null the user canceled the
// sign-in flow using the back button. Otherwise check
// response.getError().getErrorCode() and handle the error.
// ...
}
}
}
Not sure if this answers your question, but I faced a similar issue where signing worked in debug builds and wouldn't work for release builds.
In the Firebase console, if you have Google Sign in enabled you will be prompted to enter the SHA-1 Key of your build. Now, what happened in my case was I got the SHA-1 key for debug keystore and didn't do it for the release key-store.
Try,
keytool -list -v
-alias -keystore <path-to-production-keystore
and entering it on your Firebase console.

How to add onCompleteListener when signing in with Firebase Auth pre-built UI?

I am using prebuilt Firebase UI to authenticate user such as below:
val providers = arrayListOf(
AuthUI.IdpConfig.EmailBuilder().build(),
AuthUI.IdpConfig.GoogleBuilder().build())
startActivityForResult(
AuthUI.getInstance().createSignInIntentBuilder()
.setAvailableProviders(providers)
.build(),
RC_SIGN_IN)
How do I attach a OnCompleteListener during sign-in? More specifically, I want to call getAdditionalUserInfo().isNewUser() to check if the user is first time log in. I know I can add onCompleteListener if I sign in using email and password-based method, but I want to handle multiple sign-in providers using the prebuilt UI method above.
In onActivityResult you receive the result for the sign in with some data passed as Parcelable which u are already overriding for validation!
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == RC_SIGN_IN) {
// this class has all the needed data !
val response = IdpResponse.fromResultIntent(data)
if (resultCode == Activity.RESULT_OK) {
// Successfully signed in
val isNewUser = response?.isNewUser!! // flag to check if the user is first time login
}
}
}
#See class IdpResponse of package com.firebase.ui.auth:-
Dug a bit deep for you ;) Happy coding!

Get Google Refresh token from existing user auth code

I'm trying to get the Google Refresh token, the thing is that i haven't seen my current scenario anywhere, what i'm trying to accomplish is get the refresh token from a user auth token already generated by a google sign in from a native android app, basically i request every google permission i need on the app, and the the auth code from the sign in, with that auth code i send it to my Firebase functions backend, there i try to get the refresh token but i always get invalid_grant from google, so i don't know where could i be messing up
I saw that requesting oauth offline may solve the problem, but i'm sign in in the android app, so i cannot make a sign in request offline from the backend, i need the sign in and authentication to be only on the android app and i need this to make Google assistant requests over the backend and for this, the only thing missing is the refresh token
I have my google oauth2 key from google cloud console and the client initialized
var OAuth2 = google.auth.OAuth2;
var _client_id = require('./config/secrets/omni.json').installed.client_id;
var _client_secret = require('./config/secrets/omni.json').installed.client_secret;
var redirect = require('./config/secrets/omni.json').installed.redirect_uris[1];
return new OAuth2(
_client_id,
_client_secret,
redirect
);
And finally try to get the token:
function getRefreshToken(authCode, idFBUser) {
return new Promise((resolve, reject) => {
getOAuthClient().getToken(authCode, function(err, token) {
if (!err) {
console.log(`Get Token success, token: ${token}`);
getOAuthClient().setCredentials(token);
saveRefreshFirebase(idFBUser, token)
resolve(token);
} else {
console.log("Get Token error", err);
reject(err);
}
});
});
}
the error i'm getting exactly is this one: { error: 'invalid_grant', error_description: 'Bad Request' }
The method i use in the android app to request the auth code is this one:
Creating the GoogleSignIn instance
val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken(getString(R.string.default_web_client_id))
.requestEmail()
.requestId()
.requestIdToken(getClientId())
.requestServerAuthCode(getClientId())
.requestScopes(ASSISTANT_SCOPE)
.build()
googleSignInClient = GoogleSignIn.getClient(this, gso)
Calling the Sign in Intent:
val signInIntent = googleSignInClient.signInIntent
startActivityForResult(signInIntent, RESULT_GOOGLE_SIGNIN)
Handle the Sign in Result:
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == Activity.RESULT_OK) {
when (requestCode) {
RESULT_GOOGLE_SIGNIN -> {
val task = GoogleSignIn.getSignedInAccountFromIntent(data)
try {
task.result?.let { account ->
val id = account.id
val idToken = account.idToken
val authCode = account.serverAuthCode
Log.d("GoogleSignIn", "ID: $id")
Log.d("GoogleSignIn", "ID Token: $idToken")
Log.d("GoogleSignIn", "Auth code: $authCode")
btnLogin.text = "Sign Out"
loggedIn = true
} ?: Log.e("GoogleSignIn", "Exception: ${task.exception}")
} catch (e: Exception) {
Log.e("GoogleSignIn", "Catch Exception: $e")
}
}
}
}
}
and the authCode is the one i used to try to get the Refresh Token in the backend
You need to call
.requestServerAuthCode(getClientId(),true)
instead of
.requestServerAuthCode(getClientId())
If you want to get a refresh token. The javascript code you posted works with refresh tokens.
This is the easiest way to authenticate your app because all other kinds of token will expire. Refresh tokens dont expire. The Google Sign in library gives you an access code which you are already using to obtain a refresh token. You need to save this refresh token and send it to Google in order to obtain access tokens. The access token can then finally be used to make API requests.
By the way, that is actually what 'offline access' refers to. Took me a while to figure this out as well.

Firebase Google Sign-in DEVELOPER ERROR

I'm trying to use firebase google authentication for my Android App. Firstly I initialize Google Client as a documentation :
gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken(getString(R.string.default_web_client_id))
.requestEmail()
.build()
mGoogleSignInClient = GoogleSignIn.getClient(this, gso);
Google Sign-In button click listener:
googleSignInBtn.setOnClickListener({
val signInIntent = mGoogleSignInClient.signInIntent
startActivityForResult(signInIntent, RC_SIGN_IN)
})
My activity result :
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == RC_SIGN_IN) {
val task: Task<GoogleSignInAccount> = GoogleSignIn.getSignedInAccountFromIntent(data)
try {
val account = task.getResult(ApiException::class.java)
firebaseAuthWithGoogle(account)
} catch (e: ApiException) {
Log.w(TAG, "Google sign in failed status code:"+e.statusCode);
}
}
}
I added both release and debug sha-1 fingerprint to firebase console. There is no problem in debugging mode, it works. But when I'm trying in release mode , I'm getting DEVELOPER ERROR. How can I fix this problem ? Thank you.
I too am stuck at the same point in my project release and couldnt understand what was causing the trouble even after adding the SHA1 keys of debug and release. It is more than this for me. It was working fine till I started signing my build and later I realized that my debug build started failing with the same error. What it means is, I had a working solution which I want to sign with release keys and that didnt work and I was playing with proguard rules to make it work and ended up adding SHA1 release key. In this whole excitement to make it work, at some point, I lost my original functionality, i.e. my debug build also started failing with the same issue even if I didnt remove my debug key. This made to start working on this from scratch and thats when I realized that this whole process could have been lot simpler.
Workaround Answer
Following the google docs link here, I created a new activity and came up with below code and it worked with debug and release keys like a charm.
List<AuthUI.IdpConfig> providers = Arrays.asList(
new AuthUI.IdpConfig.Builder(AuthUI.GOOGLE_PROVIDER).build(),
new AuthUI.IdpConfig.Builder(AuthUI.FACEBOOK_PROVIDER).build()
);
// Create and launch sign-in intent
startActivityForResult(
AuthUI.getInstance()
.createSignInIntentBuilder()
.setAvailableProviders(providers)
.setTheme(R.style.LoginTheme)
.build(),
RC_SIGN_IN);
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == RC_SIGN_IN) {
IdpResponse response = IdpResponse.fromResultIntent(data);
if (resultCode == RESULT_OK) {
// Successfully signed in
showProgressDialog();
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
if (user != null) {
user.getIdToken(true).addOnCompleteListener(new OnCompleteListener<GetTokenResult>() {
#Override
public void onComplete(#NonNull Task<GetTokenResult> task) {
if (task.isSuccessful()) {
String idToken = task.getResult().getToken();
getCustomJWToken(idToken);
}
}
});
} else {
Toast.makeText(FirebaseLogin.this,
R.string.firebase_auth_error, Toast.LENGTH_SHORT).show();
}
hideProgressDialog();
} else {
Toast.makeText(FirebaseLogin.this, R.string.invalid_credentials,
Toast.LENGTH_SHORT).show();
}
}
}
Hope this helps somebody out there.

Categories

Resources