Dropbox can not authenticate using Xamarin.Forms - xamarin

I am trying to authenticate in Dropbox using Xamarin.Forms, I use the following code.
this.oauth2State = Guid.NewGuid().ToString("N");
var authorizeUri = DropboxOAuth2Helper.GetAuthorizeUri(OAuthResponseType.Token, AppKeyDropboxtoken, new Uri(RedirectUri), this.oauth2State, false, false, null, loginAgain);
webView = new CustomWebview
{
Source = authorizeUri.AbsoluteUri
};
webView.Navigating += this.WebViewOnNavigating;
//Grid Layout
Grid lyStack = new Grid
{
Children =
{
webView,
lyTitle,
},
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.FillAndExpand,
Padding = new Thickness(0, 20, 0, 0),
};
this.Content = lyStack;
But when I submit the App to production, I get the following error message:
Hi there,
Your production key request was declined for the following reason:
Your apps currently process the OAuth app authorization flow inside a
web view, instead of the system browser. The OAuth app authorization
flow should be processed in the user's system browser. See here for
more information:
https://www.dropbox.com/developers/documentation/http/documentation#oauth2-authorize
.
If you believe your app shouldn't have been declined, or to resubmit
your request, please email us at api-program#dropbox.com.

Using Xamarin.Auth solved the problem, that is the way it worked:
private string oauth2State;
private const string RedirectUri = "https://www.myredirecturl.com/en/";
private string AccessToken { get; set; }
private const string AppKeyDropboxtoken = "xxxxxxxxxxxxxxx";
private void openDropbox()
{
this.oauth2State = Guid.NewGuid().ToString("N");
var authorizeUri = DropboxOAuth2Helper.GetAuthorizeUri(OAuthResponseType.Token, AppKeyDropboxtoken, new Uri(RedirectUri), this.oauth2State, false, false, null, false);
//Authorize URI
OAuth2Authenticator auth = new OAuth2Authenticator
(
clientId: AppKeyDropboxtoken,
scope: "",
authorizeUrl: new Uri(authorizeUri.AbsoluteUri),
redirectUrl: new Uri(RedirectUri),
isUsingNativeUI: false
);
auth.Completed += (sender, eventArgs) =>
{
if (eventArgs.IsAuthenticated)
{
Debug.Write("IsAuthenticated . . . . . ");
// Use eventArgs.Account to do wonderful things
this.AccessToken = eventArgs.Account.Properties["access_token"].ToString();
Debug.WriteLine("AccessToken: " + this.AccessToken);
//Do Something
}
};
var presenter = new Xamarin.Auth.Presenters.OAuthLoginPresenter();
presenter.Login(auth);
}
And intialize on the plataforms the Presenter,
Android on your OnCreate method
global::Xamarin.Auth.Presenters.XamarinAndroid.AuthenticationConfiguration.Init(this, bundle);
iOs on your AppDelegate.cs
global::Xamarin.Auth.Presenters.XamarinIOS.AuthenticationConfiguration.Init();

Related

Get Azure B2C User Directory listing in Azure Function with MSAL.NET

We are currently getting a list of our Users using MS Graph and the directoryObjects/getByIds endpoint.
In the Startup of the ASP NET Core API we are using Microsoft.IdentityModel.Clients.ActiveDirectory and this code
services.AddHttpClient("GraphApi", async hc =>
{
AuthenticationContext authContext = new AuthenticationContext("https://login.microsoftonline.com/" + this.configuration["GraphApi:Tenant"]);
ClientCredential credential = new ClientCredential(this.configuration["GraphApi:ClientId"], this.configuration["GraphApi:ClientSecret"]);
hc.BaseAddress = new Uri($"https://graph.microsoft.com/v1.0/");
hc.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
AuthenticationResult result = await authContext.AcquireTokenAsync("https://graph.microsoft.com/", credential);
hc.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
});
I am creating a new Azure Function and need to do the same thing again. I was going to use the same code and Microsoft.IdentityModel.Clients.ActiveDirectory but that package has been deprecated and we should be using Microsoft.Identity.Client.
I can see lots of samples for various scenarios but they seem to be all calling the public MS Graph whereas I want to get the users from our own Azure B2C. Can someone point me at the right resources\demo.
The Azure Function will not be running in the context of a user so Managed Identity or Client Secret approach would be useful
I have implemented a similar kind of scenario for getting Azure AD user but different way in MVC
CODE
I have used these NuGet packages
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Cookies;
using Microsoft.Owin.Security.OpenIdConnect;
Startup class
public class Startup
{
string clientId = System.Configuration.ConfigurationManager.AppSettings["ClientId"];
string redirectUri = System.Configuration.ConfigurationManager.AppSettings["RedirectUri"];
static string tenant = System.Configuration.ConfigurationManager.AppSettings["Tenant"];
string authority = String.Format(System.Globalization.CultureInfo.InvariantCulture, System.Configuration.ConfigurationManager.AppSettings["Authority"], tenant);
public void Configuration(IAppBuilder app)
{
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
Microsoft.IdentityModel.Logging.IdentityModelEventSource.ShowPII = true;
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
ClientId = clientId,
Authority = authority,
RedirectUri = redirectUri,
PostLogoutRedirectUri = redirectUri,
Scope = OpenIdConnectScope.OpenIdProfile,
ResponseType = OpenIdConnectResponseType.CodeIdToken,
TokenValidationParameters = new TokenValidationParameters()
{
ValidateIssuer = false // This is a simplification
},
Notifications = new OpenIdConnectAuthenticationNotifications
{
AuthenticationFailed = OnAuthenticationFailed
},
}
);
}
private Task OnAuthenticationFailed(AuthenticationFailedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> context)
{
context.HandleResponse();
context.Response.Redirect("/?errormessage=" + context.Exception.Message);
return Task.FromResult(0);
}
HomeController
public void SignIn()
{
if (!Request.IsAuthenticated)
{
HttpContext.GetOwinContext().Authentication.Challenge( new AuthenticationProperties { RedirectUri = "/" }, OpenIdConnectAuthenticationDefaults.AuthenticationType);
}
}
public void SignOut()
{
HttpContext.GetOwinContext().Authentication.SignOut( OpenIdConnectAuthenticationDefaults.AuthenticationType, CookieAuthenticationDefaults.AuthenticationType);
}
ClaimsController
public ActionResult Index()
{
var userClaims = User.Identity as System.Security.Claims.ClaimsIdentity;
ViewBag.Name = userClaims?.FindFirst("name")?.Value;
ViewBag.Username = userClaims?.FindFirst("preferred_username")?.Value;
ViewBag.Subject = userClaims?.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value;
ViewBag.TenantId = userClaims?.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid")?.Value;
return View();
}
I tried to cover all possible implementations. Hope it will work in your case
Thanks

send the ios push notification during the Expired Provider Token error showed

I am trying to develop an mobile application using asp.net web api and xamarin forms. Getting errors in web api Project:ExpiredProviderToken
I am facing problem to the send the push notification in ios using Apns service.
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
{
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
if (UIDevice.CurrentDevice.CheckSystemVersion(8, 0))
{
var notificationSettings = UIUserNotificationSettings.GetSettingsForTypes(
UIUserNotificationType.Alert | UIUserNotificationType.Badge | UIUserNotificationType.Sound, null
);
UIApplication.SharedApplication.RegisterUserNotificationSettings(notificationSettings);
UIApplication.SharedApplication.RegisterForRemoteNotifications();
}
else
{
UIRemoteNotificationType notificationTypes = UIRemoteNotificationType.Alert | UIRemoteNotificationType.Badge | UIRemoteNotificationType.Sound;
UIApplication.SharedApplication.RegisterForRemoteNotificationTypes(notificationTypes);
}
global::Xamarin.Forms.Forms.SetFlags("CollectionView_Experimental");
global::Xamarin.Forms.Forms.Init();
LoadApplication(new App());
return base.FinishedLaunching(app, options);
}
public override void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken)
{
var IosDeviceToken = UIDevice.CurrentDevice.IdentifierForVendor.ToString();
if (!string.IsNullOrWhiteSpace(IosDeviceToken))
{
IosDeviceToken = IosDeviceToken.Trim('<').Trim('>');
var model = new IosDevice { IosDeviceId = IosDeviceToken };
string url = "http://notificationdemo.project-demo.info:8075/DeviceToken/Addtoken";
HttpClient client = new HttpClient();
string jsonData = JsonConvert.SerializeObject(model);
StringContent content = new StringContent(jsonData, Encoding.UTF8, "application/json");
var response = client.PostAsync(url, content);
var result = response.Result.StatusCode;
}
}
public override void FailedToRegisterForRemoteNotifications(UIApplication application, NSError error)
{
var model = new IosDevice { IosDeviceId = error.LocalizedDescription };
string url = "http://notificationdemo.project-demo.info:8075/DeviceToken/Addtoken";
HttpClient client = new HttpClient();
string jsonData = JsonConvert.SerializeObject(model);
StringContent content = new StringContent(jsonData, Encoding.UTF8, "application/json");
var response = client.PostAsync(url, content);
var result = response.Result.StatusCode;
//new UIAlertView("Error registering push notifications", error.LocalizedDescription, null, "OK", null).Show();
}
}
Below code is web api project
public void SendIOSNotification()
{
var options = new ApnsJwtOptions()
{
BundleId = "com.itpathsolutions.xamarin",
CertFilePath = #"D:\XamarinForms\demoapp\demoapp\demoapp.iOS\AuthKey_B95M9X635C.p8",
KeyId = "B95M9X635C",
TeamId = "M36758127B"
};
var apns = ApnsClient.CreateUsingJwt(new HttpClient(new WinHttpHandler()), options);
var push = new ApplePush(ApplePushType.Alert)
.AddBadge(1)
.AddSound("sound.caf")
.AddCustomProperty("category", "", true)
.AddCustomProperty("alert", "Good Morning iOS", true)
.AddCustomProperty("Id", "47474", true)
.AddCustomProperty("CreatedDate", DateTime.Now.ToString(), true)
.AddCustomProperty("url", "www.google.com", true)
.AddCustomProperty("content-available", "1", true)
.AddToken("CE227D98-4D25-43A6-AEF0-870DB1028772");
try
{
var response = apns.SendAsync(push).Result;
if (response.IsSuccessful)
{
Console.WriteLine("An alert push has been successfully sent!");
}
else
{
switch (response.Reason)
{
case ApnsResponseReason.BadCertificateEnvironment:
break;
// TODO: process other reasons we might be interested in
default:
throw new ArgumentOutOfRangeException(nameof(response.Reason), response.Reason, null);
}
Console.WriteLine("Failed to send a push, APNs reported an error: " + response.ReasonString);
}
}
catch (TaskCanceledException)
{
Console.WriteLine("Failed to send a push: HTTP request timed out.");
throw;
}
catch (HttpRequestException ex)
{
Console.WriteLine("Failed to send a push. HTTP request failed: " + ex);
throw;
}
}
The problem is related to server side .
Check the apple docs .
For security, APNs requires you to refresh your token regularly. Refresh your token no more than once every 20 minutes and no less than once every 60 minutes. APNs rejects any request whose token contains a timestamp that is more than one hour old. Similarly, APNs reports an error if you recreate your tokens more than once every 20 minutes.
On your provider server, set up a recurring task to recreate your token with a current timestamp. Encrypt the token again and attach it to subsequent notification requests.
The docs clear indicates that On your provider server, set up a recurring task to recreate your token with a current timestamp. Encrypt the token again and attach it to subsequent notification requests.
Also check the similar thread : iOS sending push with APNs Auth Key: suddenly "403 Forbidden: {"reason":"InvalidProviderToken"}" .

Invalid state from server. Possible forgery! error in Xamarin.Auth

Why I get this error message when trying to use the Xamarin.Auth Api?
I am running on Android Plataform and using Xamarin.Forms
OAuth2Authenticator auth = new OAuth2Authenticator
(
clientId: AppKeyDropboxtoken,
scope: "",
authorizeUrl: new Uri("https://www.dropbox.com/oauth2/authorize"),
redirectUrl: new Uri(RedirectUri),
isUsingNativeUI: false
);
auth.Completed += (sender, eventArgs) =>
{
if (eventArgs.IsAuthenticated)
{
// Use eventArgs.Account to do wonderful things
this.AccessToken = eventArgs.Account.Properties["access_token"].ToString();
Debug.WriteLine("AccessToken: " + this.AccessToken);
openDropboxFileList();
}
};
var presenter = new Xamarin.Auth.Presenters.OAuthLoginPresenter();
presenter.Login(auth);
Create a class and add this code below:
public class AuthenticatorExtensions : OAuth2Authenticator
{
public AuthenticatorExtensions(string clientId, string clientSecret, string scope, Uri authorizeUrl, Uri redirectUrl, Uri accessTokenUrl, GetUsernameAsyncFunc getUsernameAsync = null, bool isUsingNativeUI = false) : base(clientId, clientSecret, scope, authorizeUrl, redirectUrl, accessTokenUrl, getUsernameAsync, isUsingNativeUI)
{
}
protected override void OnPageEncountered(Uri url, System.Collections.Generic.IDictionary<string, string> query, System.Collections.Generic.IDictionary<string, string> fragment)
{
// Remove state from dictionaries.
// We are ignoring request state forgery status
// as we're hitting an ASP.NET service which forwards
// to a third-party OAuth service itself
if (query.ContainsKey("state"))
{
query.Remove("state");
}
if (fragment.ContainsKey("state"))
{
fragment.Remove("state");
}
base.OnPageEncountered(url, query, fragment);
}
}
Then use it as below:
[Obsolete]
private void SignInGoogleAuth()
{
try
{
string clientId = null;
string redirectUri = null;
//Xamarin.Auth.CustomTabsConfiguration.CustomTabsClosingMessage = null;
clientId = Constants.GoogleAndroidClientId;
redirectUri = Constants.GoogleAndroidRedirectUrl;
account = store.FindAccountsForService(Constants.AppName).FirstOrDefault();
var authenticator = new AuthenticatorExtensions(
clientId,
null,
Constants.GoogleScope,
new Uri(Constants.GoogleAuthorizeUrl),
new Uri(redirectUri),
new Uri(Constants.GoogleAccessTokenUrl),
null,
true);
authenticator.Completed += OnAuthCompleted;
authenticator.Error += OnAuthError;
AuthenticationState.Authenticator = authenticator;
var presenter = new Xamarin.Auth.Presenters.OAuthLoginPresenter();
presenter.Login(authenticator);
}
catch (Exception ex)
{
ShowAlert("Alert", ex.Message);
}
}
[Obsolete]
async void OnAuthCompleted(object sender, AuthenticatorCompletedEventArgs e)
{
var authenticator = sender as OAuth2Authenticator;
if (authenticator != null)
{
authenticator.Completed -= OnAuthCompleted;
authenticator.Error -= OnAuthError;
}
if (e.IsAuthenticated)
{
// If the user is authenticated, request their basic user data from Google
// UserInfoUrl = https://www.googleapis.com/oauth2/v2/userinfo
var request = new OAuth2Request("GET", new Uri(Constants.GoogleUserInfoUrl), null, e.Account);
var response = await request.GetResponseAsync();
if (response != null)
{
// Deserialize the data and store it in the account store
// The users email address will be used to identify data in SimpleDB
string userJson = await response.GetResponseTextAsync();
StaticVariables.googleProfile = JsonConvert.DeserializeObject<GoogleProfile>(userJson);
}
if (account != null)
{
store.Delete(account, Constants.AppName);
}
await store.SaveAsync(account = e.Account, Constants.AppName);
Application.Current.Properties.Remove("Id");
Application.Current.Properties.Remove("FirstName");
Application.Current.Properties.Remove("LastName");
Application.Current.Properties.Remove("DisplayName");
Application.Current.Properties.Remove("EmailAddress");
Application.Current.Properties.Remove("ProfilePicture");
Application.Current.Properties.Add("Id", StaticVariables.googleProfile.Id);
Application.Current.Properties.Add("FirstName", StaticVariables.googleProfile.GivenName);
Application.Current.Properties.Add("LastName", StaticVariables.googleProfile.FamilyName);
Application.Current.Properties.Add("DisplayName", StaticVariables.googleProfile.Name);
Application.Current.Properties.Add("EmailAddress", StaticVariables.googleProfile.Email);
Application.Current.Properties.Add("ProfilePicture", StaticVariables.googleProfile.Picture);
await Navigation.PushAsync(new GoogleProfilePage());
}
}
[Obsolete]
void OnAuthError(object sender, AuthenticatorErrorEventArgs e)
{
var authenticator = sender as OAuth2Authenticator;
if (authenticator != null)
{
authenticator.Completed -= OnAuthCompleted;
authenticator.Error -= OnAuthError;
}
Debug.WriteLine("Authentication error: " + e.Message);
}
I was getting the infamous "Possible Forgery!" error and overrode OnPageEncountered() to work around it as many have done. This turns out to be unnecessary as well as insecure.
Oauth2Authenticator is stateful so you will get this problem if you don't use the same instance of OAuth2Authenticator to invoke OnPageLoading() as was used to initiate the authentication.
To resolve, just save the instance of OAuth2Authenticator used for initiating authentication and then reuse it when calling OnPageLoading() in your OauthInterceptor.

XAMARIN FORM : How to programmatically open page and scroll down and hightlight viewcell of listview when open firebase notification

i have create app in which user assign a task to other user, when user assign a task the other use get notification that you have been assigned a new task this is my code
public void NewTaskNotification()
{
try
{
var result = "-1";
var httpWebRequest = (HttpWebRequest)WebRequest.Create("https://fcm.googleapis.com/fcm/send");
httpWebRequest.ContentType = "application/json";
httpWebRequest.Headers.Add(string.Format("Authorization: key={0}", "AAAAHiXg3GM:APA91bFhpVU5meuhVtbHUzIgd7Ualwdi8PROKbXIf0Y_tU9sxI71vPdiInOpRgribAUuqpuqn5hmaZV7ZwQTGv2KKERsKGYOwjkwZIqssWYiYNh7IrjhfnBR0XJj7t-GW7GqvEHVs0Q"));
httpWebRequest.Headers.Add(string.Format("Sender: id={0}", "129484512355"));
httpWebRequest.Method = "POST";
var payload = new
{
to = device_token.Text,
priority = "high",
content_available = true,
notification = new
{
body = "You have been assigned a new task " + "(" + TaskName.Text + ") by " + EmployeeName.Text,
title = "New Task",
icon = "Icon.png"
},
data = new
{
open_page = "NewTask",
new_task="newNotification",
},
};
App.cs
protected override void OnStart()
{
CrossFirebasePushNotification.Current.OnNotificationOpened += (s, p) =>
{
if (p.Data["open_page"].ToString() == "NewTask")
{
//var mdMasterPage = new MainPage { Title = "master page" };
//var mdp = new MasterDetailPage();
//mdp.Master = mdMasterPage;
//mdp.Detail = new NavigationPage((Page)Activator.CreateInstance(typeof(ToDo)));
//Application.Current.MainPage = mdp;
MainPage = new NavigationPage(new TabbedMainPage())
{
BarBackgroundColor = Color.FromHex("#C6488D"),
BarTextColor = Color.White
};
}
currenly when i open notification its just open the page and dont hit the speicific row of listview which is link to this notification i need to solve this issue but i am stuck how to do that
You can use the method ScrollTo.
From the documentation, you can specify the item that you want to scroll into.

How to use Xamarin.Auth in Xamarin.Forms (Shared Project for iOS and Android)?

I am trying to use Xamarin.Auth for a Facebook signin. It's all set up, but I am missing the last part. The Facebook signin is not my MainActivity, one has to click on a button in order to sign in. I don't know how to start the page for the signin. I have trying to follow this approach, but as my MainActivity isn't the Facebook signin page, it won't work. I have binded (I am following the MVVM pattern) the signin button and have implemented an interface in order to use DependencyService. My problem is when I have to implement the code of the platforms.
This is what I have tried on Android:
class LoginFBImpl : Activity, ILoginFB, IFacebookAuthenticationDelegate
{
public void LoginFB() //the method in the interface
{
var auth = new FacebookAuthenticator(FacebookAuthenticator.ClientId, FacebookAuthenticator.Scope, this);
var authenticator = auth.GetAuthenticator();
var intent = authenticator.GetUI(this);
StartActivity(intent); //Problem occurs here
}
public async void OnAuthenticationCompletedAsync(UserModel token)
{
var facebookService = new FacebookService();
var name = await facebookService.GetNameAsync(token.AccessToken);
var id = await facebookService.GetIdAsync(token.AccessToken);
var picture = await facebookService.GetPictureAsync(token.AccessToken);
}
public void OnAuthenticationCancelled()
{
}
public void OnAuthenticationFailed(string message, Exception exception)
{
}
}
iOS:
public class LoginFBImpl : UIViewController, ILoginFB, IFacebookAuthenticationDelegate
{
public void LoginFB()
{
var auth = new FacebookAuthenticator(FacebookAuthenticator.ClientId, FacebookAuthenticator.Scope, this);
var authenticator = auth.GetAuthenticator();
var viewController = authenticator.GetUI();
PresentViewController(viewController, true, null);
}
public async void OnAuthenticationCompletedAsync(UserModel token)
{
DismissViewController(true, null);
var facebookService = new FacebookService();
var name = await facebookService.GetNameAsync(token.AccessToken);
var id = await facebookService.GetIdAsync(token.AccessToken);
var picture = await facebookService.GetPictureAsync(token.AccessToken);
}
public void OnAuthenticationFailed(string message, Exception exception)
{
DismissViewController(true, null);
var alertController = new UIAlertController
{
Title = message,
Message = exception?.ToString()
};
PresentViewController(alertController, true, null);
}
public void OnAuthenticationCancelled()
{
DismissViewController(true, null);
var alertController = new UIAlertController
{
Title = "Authentication cancelled",
Message = "You didn't complete the authentication process"
};
PresentViewController(alertController, true, null);
}
}
I think it has something to do with the Activity/ViewController, but I don't know how to do it properly. When I run this I get: java.lang.NullPointerException: Attempt to invoke virtual method 'android.app.ActivityThread$ApplicationThread android.app.ActivityThread.getApplicationThread()' on a null object reference on Android, and I am expecting something similar on iOS - Haven't tested it yet as I am working on Windows.

Resources