AWS CognitoInternalErrorException - android

I am building an app where I use AWS Cognito to make user accounts. I can get it to work just fine most of the time, I have successfully made all the necessary classes and handlers to create and authenticate users and just abut everything else. However, I seem to run into this strange problem ONLY when trying to sign a user in right after their account has been created.
com.amazonaws.mobileconnectors.cognitoidentityprovider.exceptions.CognitoInternalErrorException: Authentication failed due to an internal error
If I restart the app, I can sign in just fine, so it is an issue with signing in right after an account has been created. It is very unspecific and the documentation just says "An internal error has occurred. Retry your request, but if the problem persists, contact us with details by posting a message on the AWS forums." How do you get around this?

Basically after you create an account and authenticate it, there is something cached in one of the AWS API related classes which still points towards the account not being authenticated. This error is only occurring if trying to immediately sign in after the account was created. In my case and in most cases, all of the AWS Cognito API code is contained in a manager/helper class, mine is an AWSHelper Class. To get around this issue, in my Handler after the user is confirmed, I simply recreated the AWSHelper in my activity, and I am able to sign in just fine.
GenericHandler confirmationCallback = new GenericHandler() {
#Override
public void onSuccess() {
Log.w("DMJ", "user has been confirmed!");
if (!mainActivity.updateAWS()) {
Toast.makeText(activity, "Account created! Please sign into your account", Toast.LENGTH_LONG).show();
activity.changeFragment(new SignInFragment(), "SignInFragment");
} else {
Toast.makeText(activity, "Account created!", Toast.LENGTH_LONG).show();
}
}
#Override
public void onFailure(Exception exception) {
Log.w("DMJ", "confirmation got rekt m8");
exception.printStackTrace();
}
};
In my MainActivity, I have the following method
public boolean updateAWS() {
awsHelper = new AWSHelper(this);
if (awsHelper.isSignedIn) {
changeFragment(new HomeScreenFragment(), "HomeScreenFragment");
return true;
}
return false;
}
ALSO, I have not checked but I suspect if you try to sign in the user after the the onSuccess() method entirely, the CognitoUser will be updated and able to sign in without the CognitoInternalErrorException

Related

user.delete().addOnCompleteListener not working in realtime database

I have used anonymous sign in in my app. So, whenever the user opens the app, the user gets signed in by a new anonymous account. As a result, in spite of having a very few users (around 4 to 5), there are more than 400 signed in accounts in my Firebase Authentication section. That's why I thought to delete the user (the anonymous account) when the user closes the app. For this reason, I have used
user.delete().addOnCompleteListener( new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
Toast.makeText( Activity.this, "Deleted Successfully" , Toast.LENGTH_LONG).show();
}
else {
Toast.makeText( Activity.this, "Failed" , Toast.LENGTH_LONG).show();
}
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Toast.makeText( Activity.this, "Failed to delete" , Toast.LENGTH_LONG).show();
}
});
But, the problem is NO TOAST IS DISPLAYED. So, what can be causing this problem? I don't know whether the user is being deleted or not. Also, suggest some better way to tackle this problem, if possible.
This isn't the way that anonymous accounts are meant to be used. They are expected to persist across app launches so that any per-user data you're storing will continue to be associated with the user as they come and go. Deleting the account whenever the app is backgrounded is certainly going to cause confusion for both you and the user.
If you want to do something to purge unused accounts, you should have some backend code that uses the Firebase Admin SDK that periodically deletes old user accounts by whatever criteria you decide that makes that account "old".

Auth0 Android - How to renew id_token?

I have Auth0 and cognito all wired up. I can login to the app and everything works great. Until the id_token expires, then everything fails.
What is the ODIC Conformant way to refresh/renew id_tokens?
The following code only refreshes the access token for me.
Initial auth:
WebAuthProvider.login(auth0CredentialsManager.getAuth0Account())
.withScope("openid email profile offline_access") // is offline_access required?
.withResponseType(ResponseType.ID_TOKEN | ResponseType.CODE | ResponseType.TOKEN) // I'm not sure if this is necessary to specify...
.withParameters(params)
.withAudience(String.format("https://%s/userinfo", BuildConfig.AUTH0_DOMAIN))
.start(Auth0LoginActivity.this, new AuthCallback() {
#Override
public void onFailure(#NonNull Dialog dialog) {
// Show error Dialog to user
dialog.show();
onAuth0Failure(null);
}
#Override
public void onFailure(AuthenticationException exception) {
Bugsnag.notify(exception);
onAuth0Failure(exception);
// Show error to user
}
#Override
public void onSuccess(#NonNull Credentials credentials) {
handleSignIn(credentials); //this call saves credentials using SecureCredentialsManager. If you want to see it let me know
}
});
And when I need to get a fresh id_token, I'm trying this (but it only refreshes the access token):
// auth0CredentialsManager is SecureCredentialsManager
auth0CredentialsManager.getCredentials(new BaseCallback<Credentials, CredentialsManagerException>() {
#Override
public void onSuccess(Credentials credentials) {
auth0CredentialsManager.saveCredentials(credentials);
// do more stuff here... except the id_token is expired (access token is not).
}
Do I:
Need to request offline_access or is that only for access tokens? (in my testing, it appears to only refresh access tokens).
Research/Things I've tried:
https://auth0.com/learn/refresh-tokens/ seems to indicate I just set openid scope, but I'm doing that and only getting the intial id_token. Do I need to refresh the token with prompt=none parameters and make another login call? https://auth0.com/docs/api-auth/tutorials/silent-authentication seems to indicate silent login is only needed for single page applications though.
AuthenticationAPIClient.delegationWithRefreshToken looks like it would be the right call to make, but it always throws com.auth0.android.authentication.AuthenticationException: An error occurred when trying to authenticate with the server.
Okay, here's what I've learned.
As of version 1.18.0, the call to getCredentials does NOT consider id token expiration. It only checks if the access token is expired, and if it is, it will then refresh the id_token and access token. Unfortunately the access token expiry is locked in at 24 hours unless you do additional work.
Make sure you have setOIDCCompliant to true when you create your Auth0Account instance, or else the call to renew will hit the /delegation endpoint which is now deprecated and only works if your client id is setup to support non oidc compliant calls.
One other thing to be aware of that's somewhat off topic. The SecureCredentialsManager clears out credentials if anything appears to go wrong. This isn't acceptable for me, as simply being offline and being unable to make the call causes the credentials to be cleared.

Firebase Authentication: how to verify user still exists

I am using Firebase Anonymous Authentication.
In case a user has been deleted from the Firebase console, the client still believes the user exists, as it still holds the token.
Each time I start the app, I would like to verify if the user still exists. I found out I can use the FirebaseUser.reload() function.
The documentation says that in case the user's account has been disabled or deleted, the FirebaseAuthInvalidUserException will be thrown:
https://firebase.google.com/docs/reference/android/com/google/firebase/auth/FirebaseUser.html#reload()
However this is an asyncronous function, and I am struggling finding out how to catch this exception. Can anyone show me a code sample on how to catch this exception?
I have looked all documentation, but I haven't found a sample about this.
Try this:
mFirebaseUser.reload().addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
if (e instanceof FirebaseAuthInvalidUserException) {
Log.d(TheApp.LOG_TAG, "user doesn't exist anymore");
createUser();
}
}
});

AzureAD for Android throws ADALError.AUTH_REFRESH_FAILED_PROMPT_NOT_ALLOWED

I have an app in which user authentificates in Office365 with AzureAD library for Android.
It works well, users can authentificate and work with the app. Unfortunately, after a while they start hitthing AuthenticationException with ADALError.AUTH_REFRESH_FAILED_PROMPT_NOT_ALLOWED as an error code.
I checked the source code of AzurelAD. The only place, which is throughing this issue is acquireTokenAfterValidation() method:
private AuthenticationResult acquireTokenAfterValidation(CallbackHandler callbackHandle,
final IWindowComponent activity, final boolean useDialog,
final AuthenticationRequest request) {
Logger.v(TAG, "Token request started");
// BROKER flow intercepts here
// cache and refresh call happens through the authenticator service
if (mBrokerProxy.canSwitchToBroker()
&& mBrokerProxy.verifyUser(request.getLoginHint(),
request.getUserId())) {
.......
Logger.v(TAG, "Token is not returned from backgroud call");
if (!request.isSilent() && callbackHandle.callback != null && activity != null) {
....
} else {
// User does not want to launch activity
String msg = "Prompt is not allowed and failed to get token:";
Logger.e(TAG, msg, "", ADALError.AUTH_REFRESH_FAILED_PROMPT_NOT_ALLOWED);
callbackHandle.onError(new AuthenticationException(
ADALError.AUTH_REFRESH_FAILED_PROMPT_NOT_ALLOWED, msg));
}
// It will start activity if callback is provided. Return null here.
return null;
} else {
return localFlow(callbackHandle, activity, useDialog, request);
}
}
My source code:
authenticator.getAccessTokenSilentSync(getMailService());
public class Authenticator {
..............
public String getAccessTokenSilentSync(ServiceInfo serviceInfo) {
throwIfNotInitialized();
return getAuthenticationResultSilentSync(serviceInfo).getAccessToken();
}
private AuthenticationResult getAuthenticationResultSilentSync(ServiceInfo serviceInfo) {
try {
return authenticationContext.acquireTokenSilentSync(
serviceInfo.ServiceResourceId,
Client.ID,
userIdentity.getAdUserId());
} catch (AuthenticationException ex) {
// HERE THE EXCEPTION IS HANDLED.
}
}
..............
}
Stacktrace I'm getting:
<package name>.data_access.error_handler.AuthenticationExceptionWithServiceInfo: Refresh token is failed and prompt is not allowed
at com.microsoft.aad.adal.AuthenticationContext.localFlow(AuthenticationContext.java:1294)
at com.microsoft.aad.adal.AuthenticationContext.acquireTokenAfterValidation(AuthenticationContext.java:1229)
at com.microsoft.aad.adal.AuthenticationContext.acquireTokenLocalCall(AuthenticationContext.java:1123)
at com.microsoft.aad.adal.AuthenticationContext.refreshToken(AuthenticationContext.java:1609)
at com.microsoft.aad.adal.AuthenticationContext.localFlow(AuthenticationContext.java:1261)
at com.microsoft.aad.adal.AuthenticationContext.acquireTokenAfterValidation(AuthenticationContext.java:1229)
at com.microsoft.aad.adal.AuthenticationContext.acquireTokenLocalCall(AuthenticationContext.java:1123)
at com.microsoft.aad.adal.AuthenticationContext.refreshToken(AuthenticationContext.java:1609)
at com.microsoft.aad.adal.AuthenticationContext.localFlow(AuthenticationContext.java:1261)
at com.microsoft.aad.adal.AuthenticationContext.acquireTokenAfterValidation(AuthenticationContext.java:1229)
at com.microsoft.aad.adal.AuthenticationContext.acquireTokenLocalCall(AuthenticationContext.java:1123)
at com.microsoft.aad.adal.AuthenticationContext.access$600(AuthenticationContext.java:58)
at com.microsoft.aad.adal.AuthenticationContext$4.call(AuthenticationContext.java:1072)
at com.microsoft.aad.adal.AuthenticationContext$4.call(AuthenticationContext.java:1067)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
Version of AzureAD library I'm using: 1.1.7 (to prevent blaming too old version - I've checked the changelist since from 1.1.7 to 1.1.11 and haven't found anything related to question)
Problem: Right now, I'm treating this error, as a signal to through the user to the login screen. In my opinion, it leads to a poor experience for the user. The fact that it happens very often and affects many users make it even worse.
Question: Is there anything I can do different to avoid this AuthenticationException or workaround it somehow (i.e. avoid user enters credentials once again).
Have you verified that AuthenticationContext.acquireTokenSilentSync() is truly the method that you wish to invoke?
The docs indicate that this method will explicitly not show a prompt. From the docs:
This is sync function. It will first look at the cache and automatically checks for the token expiration. Additionally, if no suitable access token is found in the cache, but refresh token is available, the function will use the refresh token automatically. This method will not show UI for the user. If prompt is needed, the method will return an exception.
The refresh token you are issued should last two weeks per this AAD book. After the refresh token expires users are expected to reauthenticate. Can you inspect net traffic with Fiddler or Charles and inspect the expiry of the tokens? If you can verify that the tokens are failing to refresh before their expiry it may indicate a bug in the AD library.
To clarify the difference in methods on AuthenticationContext - there are two categories of methods: "silent" methods (which will not present a dialog to user in the event that they need to reauthenticate), and non-silent. Non-silent methods will, in the event of requiring reauthentication (or consent) from the user, start a new Activity containing the AAD login. At that point the authentication flow is restarted.
Additionally, if you make changes to your application's registration in Azure such as adding new permission scopes your users will be required to re-grant consent for the application to continue to handle their data.
This is because you need to refresh your token and implement this in your code so the user won't be prompt to login every time the access token is expired. please check out how to implement refresh token here:
https://msdn.microsoft.com/en-us/library/azure/dn645538.aspx
Hope this helps.

OneDrive - How to retrieve authorization access data?

I develop an android application which use OneDrive API. When I connect to OneDrive, it asks me to authenticate and show an authorization page (with permission to access to my data on the cloud).
My problem is : Every time I upload data on the cloud, the application shows me the authorization page. I would like this page to not appear every time. How can we find that it already recorded please ?
Thank a lot !
When using the LiveSDK for Andriod, there is an assumption that the user is authenticated at all times when using the application, in order to preserve this flow, we require that you call LiveAuthClient.initialize(...) to renew the user credentials (without any user input) or call LiveAuthClient.login(...) in order to perform an interactive login (User entering username/password).
In the LiveSDK sample apps we see this implemented with a startup activity called SignInActivity.java Here are the relevant excerpts to perform the silent credentials renewal:
protected void onStart() {
super.onStart();
mAuthClient.initialize(Arrays.asList(Config.SCOPES), new LiveAuthListener() {
#Override
public void onAuthError(LiveAuthException exception, Object userState) {
mInitializeDialog.dismiss();
showSignIn();
showToast(exception.getMessage());
}
#Override
public void onAuthComplete(LiveStatus status, LiveConnectSession session, Object userState) {
mInitializeDialog.dismiss();
if (status == LiveStatus.CONNECTED) {
launchMainActivity(session);
} else {
showSignIn();
}
}
});
}
The launchMainActivity() function moves the user into the primary application code, this would be where your application starts in earnest. To see the full details of this sign in activity take a look at the sample app SignInActivity.java in Github

Categories

Resources