Google API Client OAuth Always Returns Canceled - android

I am trying to use the Google Fit History API and I am running into an issue where after I prompt the user for their Google account using ConnectionResult.StartResolutionForResult, I am ALWAYS getting a return code of CANCELED even though the user selects the account via the dialog. I have followed the guides found here (https://developers.google.com/fit/android/get-api-key) to the letter, as far as I can tell. I have a project in my Developers console. I have enabled the Fitness API in the console. And I have generated a client id using the debug keystore on my development machine. Here are some screenshots from developers console:
I am programming in Xamarin.Android and followed the example here. (Note that I do have Xamarin.GooglePlayServices.Fitness package installed):
https://github.com/xamarin/monodroid-samples/tree/master/google-services/Fitness/BasicHistoryApi
Here are the key areas of the code:
mClient = new GoogleApiClient.Builder (this)
.AddApi (FitnessClass.HISTORY_API)
.AddScope (new Scope (Scopes.FitnessActivityReadWrite))
.AddConnectionCallbacks (clientConnectionCallback)
.AddOnConnectionFailedListener (result => {
Log.Info (TAG, "Connection failed. Cause: " + result);
if (!result.HasResolution) {
// Show the localized error dialog
GooglePlayServicesUtil.GetErrorDialog (result.ErrorCode, this, 0).Show ();
return;
}
// The failure has a resolution. Resolve it.
// Called typically when the app is not yet authorized, and an
// authorization dialog is displayed to the user.
if (!authInProgress) {
try {
Log.Info (TAG, "Attempting to resolve failed connection");
authInProgress = true;
result.StartResolutionForResult (this, REQUEST_OAUTH);
} catch (IntentSender.SendIntentException e) {
Log.Error (TAG, "Exception while starting resolution activity", e);
}
}
}).Build ();
...
protected override void OnActivityResult (int requestCode, Result resultCode, Intent data)
{
if (requestCode == REQUEST_OAUTH) {
authInProgress = false;
if (resultCode == Result.Ok) {
// Make sure the app is not already connected or attempting to connect
if (!mClient.IsConnecting && !mClient.IsConnected) {
mClient.Connect ();
}
}
}
}
The OnFailedConnectionListener is getting called with statusCode=SIGN_IN_REQUIRED, which then causes me to call StartResolutionForResult and pop up the dialog for the user to select their Google Account. As soon as the dialog is displayed I am getting the following error in my LogCat. Note that this is before they select the account.
02-26 15:56:36.459: E/MDM(17800): [63567] b.run: Couldn't connect to Google API client: ConnectionResult{statusCode=API_UNAVAILABLE, resolution=null, message=null}
Once the user selects the account, OnActivityResult gets called and resultCode is always "Canceled", which is supposed to indicate the user dismissed the dialog but that is certainly not what happened here. Any help? It smells like something is wrong in Developer Console but after going through the guide 100 times with the same results I'm starting to go crazy.

So my issue was that I was using the wrong debug.keystore. My Mac has both Android Studio and Xamarin Studio installed. I had incorrectly assumed that Xamarin was using "~/.android/debug.keystore" but it turns out that they put theirs in "~/.local/share/Xamarin/Mono for Android/debug.keystore" changing to using the SHA1 from this key fixed my issue. For my info on Xamarin keys:
https://developer.xamarin.com/guides/android/deployment,_testing,_and_metrics/MD5_SHA1/#OSX

Use terminal to get the correct SHA for Xamarin using :
keytool -list -v -keystore ~/.local/share/Xamarin/Mono\ for\ Android/debug.keystore -alias androiddebugkey -storepass android -keypass android
As pointed out by #thedigitalsean there are different keystores for Android Studio & Xamarin (Visual Studio).
Android Studio Keystore is in location .android
Xamarin keystore is in location .local/share/Xamarin/Mono for Android
Microsoft Reference : https://learn.microsoft.com/en-us/xamarin/android/deploy-test/signing/keystore-signature?tabs=vsmac

Related

How to use Cognito identity pool with UnAuthenticatd users in Amplify for Android

I've been going through the AWS Amplify docs and tutorials for how to use Amplify and Cognito identity pools together with UNauthenticated users. The example given by the Amplify docs is:
Amplify.Auth.fetchAuthSession(
result -> {
AWSCognitoAuthSession cognitoAuthSession = (AWSCognitoAuthSession) result;
switch(cognitoAuthSession.getIdentityId().getType()) {
case SUCCESS:
Log.i("AuthQuickStart", "IdentityId: " + cognitoAuthSession.getIdentityId().getValue());
break;
case FAILURE:
Log.i("AuthQuickStart", "IdentityId not present because: " + cognitoAuthSession.getIdentityId().getError().toString());
}
},
error -> Log.e("AuthQuickStart", error.toString())
);
But in practice when I use this code - I get an error printed out in LogCat:
AuthQuickStart: FAILURE IdentityId not present because: AmplifyException {message=You are currently signed out., cause=null, recoverySuggestion=Please sign in and reattempt the operation.}
Note: I did configure AWS Cognito to support Unauthenticaed users!
I've also looked everywhere for the Amplify Android API doc to see what other APIs are supported - couldn't find any Android API docs.
And looking into the AWS Amplify.Auth methods i could not find ANY function that deals with unauthenticated users
Question:
Any clue how can i use Amplify (Android) and have AWS credentials via AWS Cognito for unauthenticated users ???
This is David from the Amplify Android team. I was actually just looking into this the other day and currently there's a hack that's required to make unauth users work.
After setting up unauth/guest users through the CLI (as you mentioned you had) you have to call the getAWSCredentials method on the underlying escape hatch once for the app to get it to work.
Here's a code snippet I'd written that you can run after Amplify.configure (and again, this only needs to be run once per app install):
AWSMobileClient mobileClient = (AWSMobileClient) Amplify.Auth.getPlugin("awsCognitoAuthPlugin").getEscapeHatch();
mobileClient.getAWSCredentials(new Callback<AWSCredentials>() {
#Override
public void onResult(AWSCredentials result) {
// Now you'll see the Identity ID and AWSCredentials in the resulting auth session object.
Amplify.Auth.fetchAuthSession(
result2 -> Log.i(TAG, result2.toString()),
error -> Log.e(TAG, error.toString()));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
#Override
public void onError(Exception e) {
// Handle the error however is best for your app
}
});
I'm working on a solution to avoid this hack right now and adding a documentation section on Unauth users to our site but in the meantime this should get it working for you.
Again note you only have to do this once and from then on out, it should just work when you call fetchAuthSession.
UPDATE: The non patched (official) version:
Amplify.Auth.fetchAuthSession(
result -> {
AWSCognitoAuthSession cognitoAuthSession = (AWSCognitoAuthSession) result;
switch (cognitoAuthSession.getIdentityId().getType()) {
case SUCCESS:
Log.i(TAG, "identity: " + cognitoAuthSession.getIdentityId().getValue());
Log.i(TAG, "credentials: " + cognitoAuthSession.getAWSCredentials().getValue(););
break;
case FAILURE:
Log.i(TAG, "FAILURE IdentityId not present because: " + cognitoAuthSession.getIdentityId().getError().toString());
}
},
error -> Log.e(TAG, "UNAUTH USERS ERR: " + error.toString()));
You wont be able to retrieve an authenticated session unless you have a logged in user.
If your Identity Pool (not User Pool) is configured for unauthenticated or guest users you can make a simple call to the GetId endpoint:
GetId
Generates (or retrieves) a Cognito ID. Supplying multiple logins will create an implicit linked account.
This is a public API. You do not need any credentials to call this API.
Request Syntax
{
"AccountId": "string",
"IdentityPoolId": "string",
"Logins": {
"string" : "string"
}
}
https://docs.aws.amazon.com/cognitoidentity/latest/APIReference/API_GetId.html
You should then be able to use the ID to retrieve a token using:
GetOpenIdToken
Gets an OpenID token, using a known Cognito ID. This known Cognito ID is returned by GetId. You can optionally add additional logins for the identity. Supplying multiple logins creates an implicit link.
The OpenID token is valid for 10 minutes.
This is a public API. You do not need any credentials to call this API.
Request Syntax
{
"IdentityId": "string",
"Logins": {
"string" : "string"
}
}
https://docs.aws.amazon.com/cognitoidentity/latest/APIReference/API_GetOpenIdToken.html

Why Firebase is unable to get PlayGames AuthCode and pass it into its Credential?

To begin with, I'm working on a Unity Game where I'm authenticating user when the game starts. My build environment is android. I'm using Firebase authentication for Google Play Games Services to authenticate user.
When the game starts in my android device or emulator, it is able to authenticate Play Games Services as well as able to connect with Firebase (I'm getting analytics data). However, when I pass the PlayGames AuthCode into Firebase.Auth Credentials, it stops executing the code (I've debug log for it). It does not throw any error in LogCat except
Firebase | server_auth_code
I tried searching web for different issues, but nothing. I checked my keys in player setting, firebase settings, OAuth 2.0 credentials on my Google API console and even check keys from my Google Play Console (which I'm not using at this stage). I have even checked my test users email addresses in Game Services and tried multiple google play games account. But issue still persist.
I'm using similar script in my other unity project where authentication works like a charm. I tried to use same script here and ended up with this issue: here. However, I solved it by removing all the packages and re-importing them into unity and changed my call functions in the script. Now, I'm stuck at this issue.
Here is cs file:
using GooglePlayGames;
using GooglePlayGames.BasicApi;
using UnityEngine.SocialPlatforms;
using System.Threading.Tasks;
public class SetFirebase : MonoBehaviour
{
string authCode;
void Start()
{
PlayGamesClientConfiguration config = new PlayGamesClientConfiguration.Builder().
RequestServerAuthCode(false /* Don't force refresh */).Build();
PlayGamesPlatform.InitializeInstance(config);
PlayGamesPlatform.Activate();
Social.localUser.Authenticate((bool success) =>
{
if (success)
{
authCode = PlayGamesPlatform.Instance.GetServerAuthCode();
Debug.Log("PlayGames successfully authenticated!");
Debug.Log("AuthCode: " + authCode);
}
else
{
Debug.Log("PlayGames SignIn Failed");
}
});
Firebase.FirebaseApp.CheckAndFixDependenciesAsync().ContinueWith(task =>
{
var dependencyStatus = task.Result;
if (dependencyStatus == Firebase.DependencyStatus.Available)
{
Debug.Log("Firebase Ready!!!");
RunFirebase();
}
else
{
Debug.LogError(System.String.Format("Could not resolve all Firebase dependencies: {0}", dependencyStatus));
}
});
}
private void RunFirebase(){
Firebase.Auth.FirebaseAuth auth = Firebase.Auth.FirebaseAuth.DefaultInstance;
Debug.Log("init firebase auth ");
Firebase.Auth.Credential credential = Firebase.Auth.PlayGamesAuthProvider.GetCredential(authCode);
Debug.Log(" passed auth code ");
auth.SignInWithCredentialAsync(credential).ContinueWith(task =>
{
if (task.IsCanceled)
{
Debug.LogError("SignInOnClick was canceled.");
return;
}
if (task.IsFaulted)
{
Debug.LogError("SignInOnClick encountered an error: " + task.Exception);
return;
}
Firebase.Auth.FirebaseUser newUser = task.Result;
Debug.LogFormat("SignInOnClick: User signed in successfully: {0} ({1})", newUser.DisplayName, newUser.UserId);
});
}
}
My LogCat executes everything till "init firebase auth" but does not execute "passed auth code" so I know there is some issue in passing the credentials. It also does not run anything inside auth.SignInWithCredentialAsync(credential).
Any help or suggestion would be highly appreciated. Thank you.
There are two things I may suggest:
1) Replace ContinueWith with ContinueWithOnMainThread. This is a Firebase Extension that will guarantee that your logic runs on the main Unity thread (which tends to resolve many Unity specific issues). I go into more detail about that here.
2) Your logic may have a race condition between the Authenticate callback and the CheckAndFixDependenciesAsync continuation. These will not necessarily run in the order that you see them in your logic.
If I were building this system, I might prefer using Coroutines and a custom yield instruction:
class Authenticate : CustomYieldInstruction
{
private bool _keepWaiting = true;
public override bool keepWaiting => _keepWaiting;
public Authenticate(Social.ILocalUser user) {
user.Authenticate((bool success)=>{
/* old authentication code here */
_keepWaiting = false;
});
}
}
Then in a coroutine have something like:
private IEnumerator InitializeCoroutine() {
/* old authentication code */
// I'm ignoring error checking for now, but it shouldn't be hard to figure in.
// I'm mostly going from memory now anyway
// start both authentication processes in parallel
var authenticate = new Authenticate(Social.localUser);
var firebaseDependenciesTask = FirebaseApp.CheckAndFixDependenciesAsync();
// wait on social
yield return authenticate;
// wait on Firebase. If it finished in the meantime this should just fall through
yield return new WaitUntil(()=>firebaseDependenciesTask.IsComplete);
RunFirebase();
}
This way my logic looks roughly synchronous whilst still maintaining the asynchronosity (spell check claims that I made up that word) of the systems you're depending on and you avoid threading related issues that arise when using ContinueWith.
Let me know if that helps!
--Patrick

Xamarin Android Web Service over HTTPS

I'm having some difficulties consuming a web service that is available only over https.
I have read posts from several other people who is having issues with achieving this as well, but none of the answers I have seen so far has fixed the problem for me, so I will try to explain my issue here and hope some of you know how to get past this obstacle.
I'm using Xamarin Studio 6.1.1 developing for Android specifically.
I have set the "HttpClient Implementation" under "Android Build" for the project to "AndroidClientHandler" (which appears to be the latest implementation and should support TLS 1.2).
I have added a web reference (not as WCF) to the web service and supplied the login information when prompted... So far everything is going as expected.
Note: I have tested the web service from a console application in Visual Studio and it works as expected.
However, when I attempt to call one of the methods of the web service I get the same error that I can see so many others have encountered before me which is this "Error: TrustFailure (The authentication or decryption has failed.)".
I have tried several of the previous posted solutions but nothing seems to help.
1.A) providing the callback function for ServicePointManager:
ServicePointManager.ServerCertificateValidationCallback += CertificateValidationCallBack;
1.B) the callback function:
private static bool CertificateValidationCallBack(
object sender,
System.Security.Cryptography.X509Certificates.X509Certificate certificate,
System.Security.Cryptography.X509Certificates.X509Chain chain,
System.Net.Security.SslPolicyErrors sslPolicyErrors)
{
// If the certificate is a valid, signed certificate, return true.
if (sslPolicyErrors == System.Net.Security.SslPolicyErrors.None)
{
return true;
}
// If there are errors in the certificate chain, look at each error to determine the cause.
if ((sslPolicyErrors & System.Net.Security.SslPolicyErrors.RemoteCertificateChainErrors) != 0)
{
if (chain != null && chain.ChainStatus != null)
{
foreach (System.Security.Cryptography.X509Certificates.X509ChainStatus status in chain.ChainStatus)
{
if ((certificate.Subject == certificate.Issuer) &&
(status.Status == System.Security.Cryptography.X509Certificates.X509ChainStatusFlags.UntrustedRoot))
{
// Self-signed certificates with an untrusted root are valid.
continue;
}
else
{
if (status.Status != System.Security.Cryptography.X509Certificates.X509ChainStatusFlags.NoError)
{
// If there are any other errors in the certificate chain, the certificate is invalid,
// so the method returns false.
return false;
}
}
}
}
// When processing reaches this line, the only errors in the certificate chain are
// untrusted root errors for self-signed certificates. These certificates are valid
// for default Exchange server installations, so return true.
return true;
}
else
{
// In all other cases, return false.
return false;
}
}
2) Creating an instance of the AesCryptoServiceProvider:
System.Security.Cryptography.AesCryptoServiceProvider b = new System.Security.Cryptography.AesCryptoServiceProvider();
If anyone can has a solution this the apparently pretty common problem, please don't hesitate to let me know, I only have so much hair...
kind regards,
Aidal
Possible known bug. Search this here for "https": https://releases.xamarin.com
[Mono], [Xamarin.iOS], [Xamarin.Android], [Xamarin.Mac] – 43566 –
“TrustFailure (The authentication or decryption has failed.) … Invalid
certificate received from server.” with “Error code: 0x5” or “Error
code: 0xffffffff800b010f” when attempting to access HTTPS servers on
ports other than 443
Bug reference: https://bugzilla.xamarin.com/show_bug.cgi?id=44708

Android: Fatal Exceptions in GoogleAuthUtil

I am working on an Android app which uses Google for authentication. Our code for fetching a token to verify a user's identity is as follows, following the "auth" sample Android project's GetNameInForeground.java:
/**
* Get a authentication token if one is not available. If the error is not recoverable then
* it displays the error message on parent activity right away.
*/
#Override
protected String fetchToken() throws IOException {
try {
return GoogleAuthUtil.getToken(mActivity, mEmail, mScope);
} catch (GooglePlayServicesAvailabilityException playEx) {
// GooglePlayServices.apk is either old, disabled, or not present.
mActivity.showErrorDialog(playEx.getConnectionStatusCode());
} catch (UserRecoverableAuthException userRecoverableException) {
// Unable to authenticate, but the user can fix this.
// Forward the user to the appropriate activity.
onError("Authorization problem with Google account", userRecoverableException);
//mActivity.startActivityForResult(userRecoverableException.getIntent(), mRequestCode);
} catch (GoogleAuthException fatalException) {
onError("Unrecoverable error " + fatalException.getMessage(), fatalException);
}
return null;
}
When logging in, we regularly receive the error "Unrecoverable error unknown." This suggests that we are getting fatalExceptions from calling GoogleAuthUtil.getToken, but we can't tell why. http://developer.android.com/reference/com/google/android/gms/auth/GoogleAuthUtil.html doesn't give much information regarding error messages.
I saw this error when I accidentally tested a binary that was signed with the Temporary Eclipse Generated credentials. I believe you need to sign the binaries with the same keys used to generate the server client-id in Google Play Console . If using Eclipse, do a signed export of the app and install.

"An error's occurred" when authenticating with Facebook's android sdk

I'm authenticating user's (or trying to) with my android app that I've been working on and all I get from the facebook dialog is that an error has occurred with no details as to what the error is. There are not exceptions being thrown for me to chase or anything of the sort. I've followed http://developers.facebook.com/docs/guides/mobile/#android to create my login dialog.
The page says use new Facebook("YOUR_APP_ID"); which results in the error, I've also tried the api key but it gives the same thing.
I'm not doing anything else except toasting but I don't even get a response in the callback until I hit the return key to leave the facebook dialog
public class Base {
private Facebook fb;
public Base() {
fb = new Facebook("app_id_here");
}
public void onCreate(Bundle b) {
super.onCreate(b);
}
private void doLogin() {
fb.authorize(this, new DialogListener() {
public void onComplete(Bundle values) {
Toast.makeText(getApplicationContext(), values.toString(),
Toast.LENGTH_LONG).show();
}
public void onFacebookError(FacebookError error) {
Toast.makeText(getApplicationContext(), error.getMessage(),
Toast.LENGTH_LONG).show();
}
public void onError(DialogError e) {
Toast.makeText(getApplicationContext(), e.getMessage(),
Toast.LENGTH_LONG).show();
}
public void onCancel() {
Toast.makeText(getApplicationContext(),
"You must be registered and signed in to perform that action",
Toast.LENGTH_LONG).show();
}
});
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
fb.authorizeCallback(requestCode, resultCode, data);
}
}
Any idea why this will be giving an error or where/how I can find what's causing the error
P.S I've also added the key hash under "Mobile and Devices" on the FB app settings page and this isn't the same problem as found over at Login failed invalid key error with Facebook SDK I've tried the suggestions over there. It doesn't work
I also faced this problem. First of all I need to know which Key Hash value you entered on facebook app if it is 'ga0RGNYHvNM5d0SLGQfpQWAPGJ8=' then that is the problem. I think you entered
keytool -exportcert -alias androiddebugkey -keystore
~/.android/debug.keystore | openssl sha1 -binary | openssl base64
this one on the terminal and you entered your own password to generate the key hash. if you done that please try do the following things also you enter the above command on terminal(I am using UBUNTU(linux). You type the command corresponding to which OS you are using) and enter the password as 'android'. This time you will get a different hey hash value. Copy that value and save it as the key hash value for your facebook app. After that check it is working or not. For me it worked. This will occur when we are using the debug key. After all this when you are about to publish this application on the Android market you will have to again change the key hash value according to the private key you are using. Try this may be this will help you.
In my case, "~/.android/debug.keystore" was the "KEY" of this problem.
Check the "debug.keystore"'s folder URL.
You must change this to right URL exactly.
And then, Run the command below..
$ cd /cygdrive/c/Users/watchout/.android <==== My Debug Keystore URL
$ keytool -exportcert -alias androiddebugkey -keystore debug.keystore | openssl sha1 -binary| openssl base
64
It asked "password", but the debug keystore doesn't have the password.
So, You can just press "enter key" and it toss me a key.
I used it then I solved this problem.
Try again, robinsonc494!

Categories

Resources