Xamarin ADAL AcquireTokenAsync not returning from await - xamarin.forms

I got this code:
public async Task<MultipleAuthResult> Authenticate(string authority, string resource, string resource2, string clientId, string returnUri)
{
MultipleAuthResult multipleAuth = new MultipleAuthResult();
var authContext = new AuthenticationContext(authority);
if (authContext.TokenCache.ReadItems().Any())
authContext = new AuthenticationContext(authContext.TokenCache.ReadItems().First().Authority);
var uri = new Uri(returnUri);
var platformParams = new PlatformParameters((Activity)Xamarin.Forms.Forms.Context);
try
{
multipleAuth.ResultBackEnd = await authContext.AcquireTokenAsync(resource, clientId, uri, platformParams);
}
catch (AdalException e)
{
return null;
}
return multipleAuth;
}
When I try to get the token, in my Xamarin.Form droid, The Azure login page pop up I can log into it. After the Azure page close, but the line
multipleAuth.ResultBackEnd = await authContext.AcquireTokenAsync(resource, clientId, uri, platformParams);
never come back for the await. No exception, no visible error.
When I retry, Azure do not ask for my login information. The login page open and close rapidly. (Cached token I think). But my code do not go out from the await.
What I do wrong?
I use:
Xamarin.Form 4.4
Microsoft.IdentityModel.Clients.ActiveDirectory 5.2.7

Related

AADSTS54005: OAuth2 Authorization code was already redeemed, please retry with a new valid code or use an existing refresh token

xamarin forms with office 365 authentification
the authentification works fine but lately i receive this error message :
AADSTS54005: OAuth2 Authorization code was already redeemed, please retry with a new valid code or use an existing refresh token.
with some research i find that i need to refresh the token. -->
https://support.workspace365.net/hc/en-us/articles/360010259114--RESOLVED-Technical-issue-Workspace-365
the question is how to refresh the token can anyone guide me.
Thank you
This my code :
public async Task<AuthenticationResult> Authenticate(string authority, string resource, string clientId, string returnUri)
{
AuthenticationResult authResult = null;
try
{
var authContext = new AuthenticationContext(authority);
if (authContext.TokenCache.ReadItems().Any())
authContext = new AuthenticationContext(authContext.TokenCache.ReadItems().First().Authority);
var uri = new Uri(returnUri);
PlatformParameters platformParams = null;
android
platformParams = new PlatformParameters((Android.App.Activity)Forms.Context);
ios
Device.BeginInvokeOnMainThread(() =>
{
UIViewController controller = new UIViewController();
controller = UIApplication.SharedApplication.KeyWindow.RootViewController;
platformParams = new PlatformParameters(controller);
});
UserDialogs.Instance.HideLoading();
Authresult need to return the token so i can use it from office 365 authentification but instead i receive the message AADSTS54005: OAuth2 Authorization...
authResult = await authContext.AcquireTokenAsync(resource, clientId, uri, platformParams);
authContext.TokenCache.Clear();
}
catch (Exception e)
{
Console.WriteLine("Execption : " + e.Message);
}
return authResult;
}
any help will be appreciated Thank you

Xamarin.Forms SecureStorage Plugin doesn't work

I'm new with Xamarin.Forms, and I'm finding a way to store data in App like: token, username. Now, I'm trying to use SecureStorgae, but the function getValue doesn't work, and I have no idea why.
My code:
public async Task CheckLogin(string usernameString, string passwordString)
{
using (var client = new HttpClient())
{
string url = "myUrl";
var json = JsonConvert.SerializeObject(new { username = usernameString, password=passwordString });
HttpContent content = new StringContent(json,Encoding.UTF8, "application/json");
var response = await client.PostAsync(url,content);
if (response.IsSuccessStatusCode)
{
var rs = JsonConvert.DeserializeObject<LoginResult>(response.Content.ReadAsStringAsync().Result);
var token = rs.result.token;
CrossSecureStorage.Current.SetValue("SessionToken",token);
CrossSecureStorage.Current.SetValue("Username", rs.result.userName);
var token1 = CrossSecureStorage.Current.GetValue("SessionToken");
await Navigation.PushAsync(new Home());
}
}
}
When my app is running, I can't get the value of SessionToken.
in iOS
Open the Entitlements.plist file and make sure that "Enable Keychain Access Groups" is checked. Also ensure that in Project->Options->iOS Bundle Signing, the Entitlements.plist is selected in Custom Entitlements for iPhoneSimulator platform.
in Android
It is required that the password is set by the application prior to use.
SecureStorageImplementation.StoragePassword = "Your Password";
For more detail you can access here

Signup user to ASP.NET Identity from Xamarin

I have been stuck all day on a stupid problem with registering a user to my application.
Here is my code once the 'Register' button is clicked:
public ICommand RegisterCommand
{
get
{
return new Command(async() =>
{
var isSuccess = await _apiServices.RegisterAsync(Email, Password, ConfirmPassword);
if (isSuccess){
Message = "Registered Successfully";
}
else
{
Message = "Retry later";
}
});
}
}
Api services Register Async method:
public async Task<bool> RegisterAsync(string email, string password, string confirmPassword)
{
try
{
System.Diagnostics.Debug.WriteLine("Email: "+email);
var client = new HttpClient();
var model = new RegisterBindingModel
{
Email = email,
Password = password,
ConfirmPassword = confirmPassword
};
var json = JsonConvert.SerializeObject(model);
HttpContent content = new StringContent(json);
// content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
var response = await client.PostAsync("http://localhost:63724/api/Account/Register", content);
if (response.IsSuccessStatusCode)
{
return true;
}
return false;
}
catch (Exception e)
{
System.Diagnostics.Debug.WriteLine("Error: "+e);
throw;
}
}
}
The Error that I get is:
System.Net.Http.HttpRequestException: An error occurred while sending the request ---> System.Net.WebException: Error: ConnectFailure (Connection refused) ---> System.Net.Sockets.SocketException: Connection refused
at System.Net.Sockets.Socket.Connect (System.Net.EndPoint remoteEP) [0x000b6] in <6c708cf596db438ebfc6b7e012659eee>:0
at System.Net.WebConnection.Connect (System.Net.HttpWebRequest request) [0x0016d] in <6c708cf596db438ebfc6b7e012659eee>:0
--- End of inner exception stack trace ---
To me this is very frustrating as I can register a use using Postman with the exact same localhost address. I am following Houssem Dellai's Xamarin.Forms mvc web api tutorials which can be found here
I had an issue with httpclient during the development of my app. I believe there was an issue with the cross-platform implementation of the httpclient class. iOS didn't know how to handle it.
Instead I implemented a very simple httpclient library called flurl: http://tmenier.github.io/Flurl/
First, you will need to install flurl in all project directories (iOS, Android, and the PCL) then the implementation is very simple.
using Flurl;
using Flurl.Http;
public async Task<User> CreateUserAsync(RegisterUserModel userModel)
{
string url = "your/backend/here";
//resp is a user object received and automatically converted into a c# object through the use of .ReceiveJson<typeofobject>();
var resp = await (url).PostJsonAsync(userModel)
.ReceiveJson<User>();
if (resp.LoginSession != null)
{
//Raise my registered event to let other classes know to proceed
OnUserRegistered(resp);
}
return resp;
}
As you can see it makes httpclient implementation very simple. Hopefully this helps.

ADAL 3 Token Persistence

I am lost after reading to many posts on the web, and need some advice.
I use ADAL 3.17.1 in my Xamarin.Forms project. Now with ADAL3, the refresh token and the AcquireTokenByRefreshTokenAsync are no longer available and are internally handled. But this Refresh token in stores in memory only and when IOS app goes in the background, or when the application is close and reopened, the user needs to log again.
Is is possible to let the user log once in the morning and keep the token valid for 8-10 hours?. And not asking to log in when the app start or resume in the next 8-10 hours? I can't find post on that. All posts are with use of Refresh token...
Here is the code in my Authenticator class that run in IOS:
public class Authenticator_iOS : IAuthenticator
{
public async Task<MultipleAuthResult> Authenticate(string authority, string resource, string resource2, string clientId, string returnUri)
{
MultipleAuthResult multipleAuth = new MultipleAuthResult();
var authContext = new AuthenticationContext(authority, new CustomTokenCache());
if (authContext.TokenCache.ReadItems().Any())
authContext = new AuthenticationContext(authContext.TokenCache.ReadItems().First().Authority);
var controller = UIApplication.SharedApplication.KeyWindow.RootViewController;
var uri = new Uri(returnUri);
var platformParams = new PlatformParameters(controller);
platformParams.PromptBehavior = PromptBehavior.Auto;
try
{
multipleAuth.ResultBackEnd = await authContext.AcquireTokenAsync(resource, clientId, uri, platformParams); // Token for backend
multipleAuth.ResultGraph = await authContext.AcquireTokenAsync(resource2, clientId, uri, platformParams); // Token for Graph query
}
catch (Exception e)
{
return null;
}
return multipleAuth;
}
public void SingOut(string authority)
{
//Token
var authContext = new AuthenticationContext(authority);
if (authContext.TokenCache.ReadItems().Any())
{
authContext.TokenCache.Clear();
}
//Webview cookie
NSHttpCookieStorage CookieStorage = NSHttpCookieStorage.SharedStorage;
foreach (var cookie in CookieStorage.Cookies)
{
CookieStorage.DeleteCookie(cookie);
}
}
}
Looks like you're initializing a new cache instance every time your method fires.
var authContext = new AuthenticationContext(authority, new CustomTokenCache());
which renders this check moot:
if (authContext.TokenCache.ReadItems().Any())
Just remove initializing CustomTokenCache altogether, i have a feeling it will persist by default.
Do this instead:
var authContext = new AuthenticationContext(commonAuthority);
if (authContext.TokenCache.ReadItems().Count() > 0)
{
authContext = new AuthenticationContext(
authContext.TokenCache.ReadItems().First().Authority);
}

AADSTS70001: Application '574c1791-d632-4180-91e4-38094a8a3a77' is not supported for this API version

I am trying to use office365 api in my single page .net application not an mvc. I got the source code for mvc .net project C# in the website itself.
public async Task<ActionResult> SignIn()
{
string authority = "https://login.microsoftonline.com/common";
string clientId = System.Configuration.ConfigurationManager.AppSettings["ida:ClientID"];
AuthenticationContext authContext = new AuthenticationContext(authority);
// The url in our app that Azure should redirect to after successful signin
Uri redirectUri = new Uri(Url.Action("Authorize", "Home", null, Request.Url.Scheme));
// Generate the parameterized URL for Azure signin
Uri authUri = await authContext.GetAuthorizationRequestUrlAsync(scopes, null, clientId, redirectUri, UserIdentifier.AnyUser, null);
// Redirect the browser to the Azure signin page
return Redirect(authUri.ToString());
}
// Note the function signature is changed!
public async Task<ActionResult> Authorize()
{
// Get the 'code' parameter from the Azure redirect
string authCode = Request.Params["code"];
string authority = "https://login.microsoftonline.com/common";
string clientId = System.Configuration.ConfigurationManager.AppSettings["ida:ClientID"]; ;
string clientSecret = System.Configuration.ConfigurationManager.AppSettings["ida:ClientSecret"]; ;
AuthenticationContext authContext = new AuthenticationContext(authority);
// The same url we specified in the auth code request
Uri redirectUri = new Uri(Url.Action("Authorize", "Home", null, Request.Url.Scheme));
// Use client ID and secret to establish app identity
ClientCredential credential = new ClientCredential(clientId, clientSecret);
try
{
// Get the token
var authResult = await authContext.AcquireTokenByAuthorizationCodeAsync(
authCode, redirectUri, credential, scopes);
// Save the token in the session
Session["access_token"] = authResult.Token;
// Try to get user info
Session["user_email"] = GetUserEmail(authContext, clientId);
return Redirect(Url.Action("Inbox", "Home", null, Request.Url.Scheme));
}
catch (AdalException ex)
{
return Content(string.Format("ERROR retrieving token: {0}", ex.Message));
}
}
I converted the code to vb.net and i am receiving bad request error stating that my application is not supported for this api version when executed. The code is in WebForm1.aspx and the redirect uri link is to webform2.aspx
Private Sub SignIn()
Dim authority As String = "https://login.microsoftonline.com/common"
Dim clientId As String = System.Configuration.ConfigurationManager.AppSettings("ida:ClientID")
Dim authContext As New AuthenticationContext(authority)
Dim redirectUri As New Uri("http://localhost:26683/WebForm2.aspx")
Dim authUri As Uri = authContext.GetAuthorizationRequestURL("https://outlook.office.com/mail.read", clientId, redirectUri, UserIdentifier.AnyUser, Nothing)
Response.Redirect(authUri.ToString())
End Sub
How ever i have registered the application.In fact when i used the same client id and client secret for the mvc application it is executed without any error but when i use it in my single web application it throws this error.
Please help.What am i doing wrong

Resources