How to implement google sign in - android

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.

Related

prevent google credentials save in 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()

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!

GoogleSignInClient return 8 (internal error)

I'm trying to connect my game to Google Play Games Services, but when I try to login, it always returns me an error code 8 (internal error).
The code is copy pasted from Google example:
lateinit var signInClient: GoogleSignInClient
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.layout_settings)
settings_login.setOnClickListener { login() }
signInClient = GoogleSignIn.getClient(this,
GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN).build()
)
}
private fun login() {
startActivityForResult(signInClient.signInIntent, 9001)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode != 9001) {
return
}
val task = GoogleSignIn.getSignedInAccountFromIntent(intent)
try {
val account = task.getResult(ApiException::class.java)
onConnected(account)
} catch (apiException: ApiException) {
var message: String? = apiException.message
if (message == null || message.isEmpty()) {
message = getString(R.string.signin_other_error)
}
onDisconnected()
AlertDialog.Builder(this)
.setMessage(message)
.setNeutralButton(android.R.string.ok, null)
.show()
}
}
In Google Play Console I've linked my game with debug keystore SHA-1.
I've checked everythin mentioned in Troubleshooting guide, but I still get this message again and again.
Does someone faced this issue? Any ideas how to debug it?
EDIT:
I found that it actually logs me in - if I restart game, method signInSilently() will be successful. However, it still shows this error 8 when I logout and try to log in manually. Could it be the problem with login activity overlay?
Oh, and I checked api access in Google Play Api Console - it shows that api actually receives my calls and it doesn't mention any errors.
EDIT 2: I've added requestEmail() to GoogleSignInOptions.Builder, and it shows me overlay with access request. However, it still fails in GoogleSignIn.getSignedInAccountFromIntent(intent).getResult(ApiException::class.java) with same error (8 - internal error).
It looks like this bug in Google Play Services 12.2.21:
https://github.com/googlesamples/google-services/issues/358
Google is supposed to be working on a fix for release over the air soon..
it's maybe late but I found the reason. It fixed in my case and I see your code has same problem.
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
...
val task = GoogleSignIn.getSignedInAccountFromIntent(intent)
...
}
The intent you passed to the method getSignedInAccountFromIntent() is not the intent that returned by onActivityResult. The intent you passed come from activity, so you need to change it to
val task = GoogleSignIn.getSignedInAccountFromIntent(data)
"data" is the intent returned by onActivityResult
I didn't found the reason of this error, but I found an (ugly) workaround. I noticed, that when I restart game after manual login, even if there was this error, signInSilently() method works fine, which means that API actually authenticate me and fails later. So in catch block I'm checking for status code of error, and, if it's (8 - internal error), I'm requesting last signed in account. If account is present, I assume user to be logged in.
It's really dirty but I'm out of ideas.
//onActivityResult
val task = GoogleSignIn.getSignedInAccountFromIntent(intent)
try {
val account = task.getResult(ApiException::class.java)
onSuccess(account)
} catch (apiException: ApiException) {
val acc = GoogleSignIn.getLastSignedInAccount(context)
if (apiException.statusCode == 8 && acc != null && acc.email != null) {
onSuccess(account)
} else {
onFail(apiException)
}
}
I have a client with that error. Only ONE! With a Galaxy S9. Nothing happens when clicking on the Sign In button (startActivityForResult -> GoogleSignIn.getClient.getSignInIntent)

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.

Google signIn tokenId is invalid_token

I need to get google+ signIn tokenId.
Here is my code:
var mGSO = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken(WEB_CLIENT_ID)//from developer console
.requestEmail()
.build()
mGoogleApiClient = GoogleApiClient.Builder(mActivity)
.enableAutoManage(mActivity, this)
.addApi(Auth.GOOGLE_SIGN_IN_API, mGSO)
.build()
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
val result = Auth.GoogleSignInApi.getSignInResultFromIntent(data)
var tokenId = result.signInAccount.idToken
}
So I successfully get tokenId, but when I try to check it here (https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=) I receive message:
{
"error": "invalid_token",
"error_description": "Invalid Value"
}
Token the same every time I try to get it!
What is happening?
Any idea how to fix this?
UPDATE
found this issue: https://github.com/PhilipGarnero/django-rest-framework-social-oauth2/issues/61
I was using the wrong google token from my sign-in on iOS. I
originally used user.authentication.idToken which is wrong, and will
not work.
The correct token is user.authentication.accessToken.
but i cant find any similar accessToken at GoogleSignInResult object....
UPDATE 2
i am using debug apk.
here is my button click code:
fun onGooglePlusClicked(v: View) {
val signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient)
mActivity?.startActivityForResult(signInIntent, GOOGLE_SIGN_IN)
}
Very important thing
Google needs to update the documentation, because it is misleading.
Either you are on iOS, or Android, you have to send the accessToken to the backend and not the idToken
You can get the accessToken from user object (e.g. val accessToken = user.authentication.accessToken)
For example, if you want to get user info, try this GET request:
https://www.googleapis.com/oauth2/v3/tokeninfo?access_token={access_token}
The answer was founded here:
https://developers.google.com/identity/protocols/CrossClientAuth
key words: GoogleAuthUtil.getToken()
so, here is my updated code:
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
val result = Auth.GoogleSignInApi.getSignInResultFromIntent(data)
Observable.create(Observable.OnSubscribe<String> {
var **accessTokent** = GoogleAuthUtil.getToken(mActivity!!, result.signInAccount.account, "oauth2:" + Scopes.PLUS_LOGIN)
//send token to server
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe()
}
hope this will help someone :)
Answer in 2021:
I've had the same problem.
For me clearing app data completely solved the issue.
Seemed like an old expired token got stuck.
Also the id token should be verified here
https://oauth2.googleapis.com/tokeninfo?id_token=
In my case, I was testing this in Unity and I copied the idToken value that I printed in logcat. Turns out, there is some character or size limit (1024 bytes?) for a line in either adb logcat or Unity's Debug.Log() method. So the printed token value was getting truncated. What I did then for testing was that I copied the token value to clipboard during runtime and then checked again with the tokeninfo endpoint https://oauth2.googleapis.com/tokeninfo?id_token= and it was accepted.

Categories

Resources