OneDrive - How to retrieve authorization access data? - android

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

Related

(MSAL) Force require password login with Microsoft account - Android Studio

I'm working on an app for android phones to be used by multiple users, where they can log in with google or microsoft accounts, to connect the app info to microsoft teams and/or sharepoint if desired.
I'm coding on Android Studio, using MSAL supporting multiple accounts.
Underneath is a method I have to remove accounts from the current PublicClientApplication.MultipleAccountPublicClientApplication. It also returns the result for each removal, if they were removed or not, in a list of booleans.
When testing, all the accounts are removed successfully, but when signing in again and the microsoft sign in intent is opened, the accounts can just be clicked to sign in without password. Signing out seems kind of pointless because of this, since one can just select their user and be logged in again right away. Is it possible to require or force the Microsoft intent to log in with password?
public CompletableFuture<List<Boolean>> signOutAll() {
List<Boolean> removedList = new ArrayList<>();
CompletableFuture<List<Boolean>> future = new CompletableFuture();
for (IAccount account : accountList) {
mPCA.removeAccount(account,
new IMultipleAccountPublicClientApplication.RemoveAccountCallback() {
#Override
public void onRemoved() {
removedList.add(true);
if (accountList.size() == removedList.size()) {
future.complete(removedList);
}
}
#Override
public void onError(#NonNull MsalException exception) {
removedList.add(false);
if (accountList.size() == removedList.size()) {
future.complete(removedList);
}
}
});
}
return future;
}
--
Thank you,
Didrik
This is happening because MSAL automatically refreshes your token after expiration. When user opens your app it checks if that token is already present and valid. So you can remove the token from the Android KeyStore in onStop().
So yes you also need to remove the cache as well to remove the account from the cache, find the account that need to be removed and then call PublicClientApplication.removeAccount()
Set<IAccount> accounts = pca.getAccounts().join();
IAccount accountToBeRemoved = accounts.stream().filter(
x -> x.username().equalsIgnoreCase(
UPN_OF_USER_TO_BE_REMOVED)).findFirst().orElse(null);
pca.removeAccount(accountToBeRemoved).join();
Read more here.
On Android we basically don't have any control on the cookies because they are shared with external Chrome app and because of that it is not accessible. If you want the user to enter the password again then you should do this: AcquireTokenInteractive(scopes).WithPrompt(Prompt.ForceLogin);

How to verify user is authenticated entire app Xamarin Form

I'm new with Xamarin form, my question is how can I check user is logged in for entire app, example every time when users go to a new page, it checks for authent. I tried successfully for every page check for auth but is there any another ways to do it? I did some research on internet and some said that i have to auth on the App.cs on OnStart() but the event is not raise when i go to the next page, it starts only when user open the app.
Here is my code, I'm using Google auth.
On the logged in page (HomePage):
public HomePage(NetworkAuthData networkAuthData)
{
if (string.IsNullOrEmpty(networkAuthData.Id))
{
//Always require user authentication
//Application.Current.MainPage.Navigation.PopAsync();
Application.Current.MainPage = new NavigationPage(new SocialLoginPage(oAuth2Service));
}
else
{
BindingContext = networkAuthData;
InitializeComponent();
}
}
It works but when i move these code to app.cs on OnStart() it just run once when opened the app.

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.

AppAuth Relogin

After some back and forth I finally got this to work but I had to use version 0.2.0 because I followed the google guide presented in the Readme.
Anyway, Im struggling with handling what will happen when the oAuth token times out. Then it needs to open the browser again to log in or is there a background process available for this as it automatically redirects back to the app because the server remembers the user so there is no need for a new username/password input?
Im getting a refresh token like this :
if(mAuthService == null){
mAuthService = new AuthorizationService(context);
}
mAuthState.performActionWithFreshTokens(mAuthService, new AuthState.AuthStateAction() {
#Override public void execute(
String accessToken,
String idToken,
AuthorizationException ex) {
if (ex != null) {
return;
}
// Getting the access token...
}
});
Thats working fine but after the user is idle for some time it wont work. How to handle this properly?
Solution for my problem was this:
I changed to using offline_access for the token in the scope. Depending on the site/service you're login into if they accept it or not. For me it was accepted and will keep the user logged in for a long time and removes the need to re-login.

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.

Categories

Resources