OAuth2 and UWP Xamarin.Forms - android

Can any one help me with this problem?
I don`t know how to use OAuth2 with UWP.
For example, on Andriod code of authentication looks like this:
[assembly: ExportRenderer(typeof(LoginPage), typeof(LoginPageRenderer))]
namespace TestTask.Droid
{
class LoginPageRenderer : PageRenderer
{
private static bool _isShown;
protected override void OnElementChanged(ElementChangedEventArgs<Page> e)
{
base.OnElementChanged(e);
if (_isShown) return;
_isShown = true;
var activity = this.Context as Activity;
var auth = new OAuth2Authenticator(
clientId: "someId",
scope: "",
authorizeUrl: new Uri("https://oauth.vk.com/authorize"),
redirectUrl: new Uri("https://oauth.vk.com/blank.html"));
auth.Completed += (sender, eventArgs) => {
if (eventArgs.IsAuthenticated)
{
AuthInfo.Token = eventArgs.Account.Properties["access_token"].ToString();
AuthInfo.UserID = eventArgs.Account.Properties["user_id"].ToString();
}
else
{
// The user cancelled
}
};
activity?.StartActivity((Intent)auth.GetUI(activity));
}
}
}
so, on android the solution is in this method
protected override void OnElementChanged(ElementChangedEventArgs<Page> e)
and in this row fo code
activity?.StartActivity((Intent)auth.GetUI(activity));
My question is: How I can do the same in UWP, or how I can make it work in UWP?

Thank you all! I`ve found a solution for my purpose for UWP platform.
[assembly: ExportRenderer(typeof(LoginPage), typeof(LoginPageRenderer))]
namespace TestTask.UWP
{
public class LoginPageRenderer : PageRenderer
{
private Windows.UI.Xaml.Controls.Frame _frame;
private bool _isShown;
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Page> e)
{
base.OnElementChanged(e);
if (_isShown) return;
_isShown = true;
if (Control == null)
{
WindowsPage windowsPage = new WindowsPage();
var auth = new OAuth2Authenticator(
clientId: "someID",
scope: "",
authorizeUrl: new Uri("https://oauth.vk.com/authorize"),
redirectUrl: new Uri("https://oauth.vk.com/blank.html"));
_frame = windowsPage.Frame;
if (_frame == null)
{
_frame = new Frame();
//_frame.Language = global::Windows.Globalization.ApplicationLanguages.Languages[0];
windowsPage.Content = _frame;
SetNativeControl(windowsPage);
}
auth.Completed += (sender, eventArgs) => {
if (eventArgs.IsAuthenticated)
{
AuthInfo.Token = eventArgs.Account.Properties["access_token"].ToString();
AuthInfo.UserID = eventArgs.Account.Properties["user_id"].ToString();
}
else
{
// The user cancelled
}
};
Type pageType = auth.GetUI();
_frame.Navigate(pageType, auth);
Window.Current.Activate();
}
}
}
}
Please mark it solved!

My question is: How I can do the same in UWP, or how I can make it work in UWP?
I'm not sure whether the Xamarin.Auth supports UWP or not, but for UWP, we can use Web authentication broker for OAuth, you can check the official WebAuthenticationBroker sample, it's not xamarin, but you can code it in native UWP project and use Custom renderer to do the same thing in Xamarin.

Xamarin.Auth supports UWP for Standard/Traditional quite long.
Xamarin.Forms support was recently added and is not tested thoroughly (1.5.0-alpha)

Related

RedirectURI does not redirect for Mobile using WebAuthenticator.AuthenticateAsync

I'm attempting to use Xamarin.Essentials.WebAuthenticator to Authenticate using Azure AD which in turn should call back to my mobile app with an WebAuthenticatorResult. The process works up to the point where the Callback URI should callback into my app.
Command in Mobile App is fired calling the AuthenticateAsync method.
A new web browser opens on the mobile and I am prompted to enter my Microsoft Credentials
Sign in using my organisations user credentials.
Sign in successful.
Error message displays
The callback URI is never fired and the only option I have is to close the browser which then throws an exception in my app, this is expected when the process fails or the user closes the browser. The authentication result is never returned in my app.
What I expect to happen is once the authentication was successful the browser would redirect the browser to the RedirectURI and my mobile app would handle it.
Am I misunderstanding how this is supposed to work or have I misconfigured something?
WebAuthenticator called from my ViewModel
async Task<bool> SSOLogin()
{
ErrorMessage = string.Empty;
try
{
var authRequestUrl = new Uri("https://myapps.microsoft.com/signin/2borno2-1234-abcd-baba-42aaa70ab1da?tenantId=ab12ac17-4321-acbd-1234-72aae60ed1ca6");
var callbackUrl = new Uri("mobile://myapp");
var authResult = await WebAuthenticator.AuthenticateAsync(new WebAuthenticatorOptions
{
Url = authRequestUrl,
CallbackUrl = callbackUrl,
PrefersEphemeralWebBrowserSession = true
});
var accessToken = authResult?.AccessToken;
return true;
}
catch(Exception e)
{
var msg = e.Message;
}
finally
{
IsBusy = false;
}
return false;
}
Activity to handle callback URI (mobile://myapp)
[Activity(NoHistory = true, LaunchMode = LaunchMode.SingleTop, Exported = true)]
[IntentFilter(new[] { Android.Content.Intent.ActionView },
Categories = new[] { Android.Content.Intent.CategoryDefault, Android.Content.Intent.CategoryBrowsable },
DataScheme = "mobile")]
public class WebAuthenticationCallbackActivity : Xamarin.Essentials.WebAuthenticatorCallbackActivity
{
}
Azure AD Application Setup
N.B. the tenant Id and client ids are not the actual ones I'm using. I'm confident these are working as the browser in the mobile app takes me to the correct log in page and the error message displays the application name I've set up in Azure AD.
The sign-on URL error in your screenshot ("Undefined sign-on url for app") typically indicates that you need to set the Home Page URL under the app registration's branding tab.
From your other screenshot I am unable to tell whether you have selected the checkbox next to the mobile://myapp URL to make it the default. If you haven't done that and have multiple Redirect URIs added, the first one will get selected by default.
In the end I used the Microsoft.Identity.Client nuget package instead and configured the Mobile app platforms in Azure AD.
public class AzureADTokenService
{
// Replace these with your details
readonly string AndroidAppId = "YOUR.APP.NAME";
readonly string GeneratedAndroidAppSignature = "1234567890asdfghjkl";
readonly string iOSAppId = "YOUR.PACKAGE.BUNDLENAME";
readonly string AzureADClientID = "aaaaaaaa-1111-2222-3333-444444444444";
readonly string AzureADTenantID = "aaaaaaaa-1111-2222-3333-444444444444";
private IParentWindowLocatorService _parentWindowLocatorService;
readonly List<string> Scopes = new List<string> { "user.read" };
private IPublicClientApplication _pca;
string RedirectUri
{
get
{
if (DeviceInfo.Platform == DevicePlatform.Android)
return $"msauth://{AndroidAppId}/{GeneratedAndroidAppSignature}";
else if (DeviceInfo.Platform == DevicePlatform.iOS)
return $"msauth.{iOSAppId}://auth";
return string.Empty;
}
}
public AzureADTokenService(IParentWindowLocatorService parentWindowLocatorService)
{
_parentWindowLocatorService = parentWindowLocatorService;
// Create tha application
_pca = PublicClientApplicationBuilder.Create(AzureADClientID)
.WithIosKeychainSecurityGroup("com.microsoft.adalcache")
.WithRedirectUri(RedirectUri)
.WithAuthority(AzureCloudInstance.AzurePublic, AzureADTenantID)
.Build();
}
public async Task<string> SignInAsync()
{
AuthenticationResult result;
try
{
var accounts = await _pca.GetAccountsAsync();
var firstAccount = accounts.FirstOrDefault();
// Attempt to sign in silently using existing cached tokens
if (firstAccount != null)
result = await _pca.AcquireTokenSilent(Scopes, firstAccount).ExecuteAsync();
else
{
var builder = _pca.AcquireTokenInteractive(Scopes)
.WithUseEmbeddedWebView(true);
if (DeviceInfo.Platform == DevicePlatform.Android)
{
var windowLocatorService = _parentWindowLocatorService.GetCurrentParentWindow();
builder = builder.WithParentActivityOrWindow(windowLocatorService);
}
result = await builder.ExecuteAsync();
}
}
catch (MsalUiRequiredException)
{
var builder = _pca.AcquireTokenInteractive(Scopes)
.WithUseEmbeddedWebView(true);
if (DeviceInfo.Platform == DevicePlatform.Android)
{
var windowLocatorService = _parentWindowLocatorService.GetCurrentParentWindow();
builder = builder.WithParentActivityOrWindow(windowLocatorService);
}
result = await builder.ExecuteAsync();
}
if (result == null)
{
return null;
}
return result.AccessToken;
}
public async Task<bool> SignOutAsync()
{
try
{
var accounts = await _pca.GetAccountsAsync();
// Go through all accounts and remove them.
while (accounts.Any())
{
await _pca.RemoveAsync(accounts.FirstOrDefault());
accounts = await _pca.GetAccountsAsync();
}
return true;
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
return false;
}
}
}

Backbutton on ZXing Scanner doesn´t works (Xamarin Forms)

im trying to implement a Barcode Scanner on my project in Xamarin Forms. When i press the back button on the scanning page my app crash. I am getting the following error: System.NullReferenceException: 'Object reference not set to an instance of an object.'
This is my code:
ScanService.cs
public interface ScanningService
{
Task<string> ScanAsync();
}
My code behind:
var scanner = DependencyService.Get<ScanningService>();
var result = await scanner.ScanAsync();
if (result != null){.....}
QRscanningService (On Android):
class QrScanningService : ScanningService
{
public async Task<string> ScanAsync()
{
var optionsCustom = new MobileBarcodeScanningOptions();
var scanner = new MobileBarcodeScanner()
{
TopText = "Acerca la cámara",
BottomText = "Toca la pantalla para enfocar",
};
var scanResult = await scanner.Scan(optionsCustom);
return scanResult.Text;
}
}
Any contribution will be apreciated.
I believe the error occurs inside QRscanningService (On Android).
It is because you're trying to use "Text" from scanResult and scanResult is null
To avoid this, change the last line to something like this:
return scanResult == null ? null: scanResult.Text;
I solved it with the following code on my code behind:
var overlay = new ZXingDefaultOverlay
{
ShowFlashButton = true,
TopText = "Toca la pantalla para enfocar",
BottomText = string.Empty
};
overlay.BindingContext = overlay;
scanPage = new ZXingScannerPage(null, overlay);
overlay.FlashButtonClicked += (s, ed) =>
{
scanPage.ToggleTorch();
};
scanPage.OnScanResult += (result) =>
{
scanPage.IsScanning = false;
Device.BeginInvokeOnMainThread(() =>
{
_ = Navigation.PopModalAsync();
try
{
TxtidR.Text = result.Text;
}
catch (Exception)
{
throw;
}
});
};
await Navigation.PushModalAsync(scanPage);
var scanner = DependencyService.Get<ScanningService>();
}
I hope it works for you!

How to convert Cordova Android app to iOS?

I have developed the Android app with HTML5,CSS and Javascript using Cordova.
In this I have used some native plugins like geolocation etc.
I want to convert this app to iOS.
Will the app directly be converted to iOS without changing any code?
What should I do?
I know there is Phonegap build services but I have not used Phonegap to develop the app.
I do not have a Mac machine.
Thanks,
Ext.application({
viewport: {
autoBlurInput: false
},
name:'MyApp',
controllers:[],
stores:[],
models:[],
views:[],
launch:function(){
Ext.Msg.defaultAllowedConfig.showAnimation = false;
if (Ext.os.is.Android) {
Ext.Viewport.on('painted', function () {
Ext.Viewport.setHeight(window.innerHeight);
});
}
Ext.Viewport.add(Ext.create('MyApp.view.LoginView'));
}
});
Ext.define('Override.util.PaintMonitor', {
override: 'Ext.util.PaintMonitor',
constructor: function (config) {
return new Ext.util.paintmonitor.CssAnimation(config);
}
});
Ext.define('Override.util.SizeMonitor', {
override: 'Ext.util.SizeMonitor',
constructor: function (config) {
var namespace = Ext.util.sizemonitor;
if (Ext.browser.is.Firefox) {
return new namespace.OverflowChange(config);
} else if (Ext.browser.is.WebKit || Ext.browser.is.IE11) {
return new namespace.Scroll(config);
} else {
return new namespace.Default(config);
}
}
});

Xamarin android facebook auth NullReferenceException

I am faced with problem when trying to authenticate my app via facebook. After entering a username and password in the facebook form, I caught a NullReferenceException.
I've noticed that it happens only when I compile with Android 6.0.
[assembly: ExportRenderer(typeof(FirstPage), typeof(FirstPageRenderer))]
namespace Dating.Droid.Renderers
{
public class FirstPageRenderer : PageRenderer
{
public FirstPageRenderer()
{
var activity = this.Context as Activity;
if (activity != null)
{
var auth = new OAuth2Authenticator(
clientId: "MyFacebookId", // your OAuth2 client id
scope: "", // the scopes for the particular API you're accessing, delimited by "+" symbols
authorizeUrl: new Uri("https://m.facebook.com/dialog/oauth/"),
redirectUrl: new Uri("http://www.facebook.com/connect/login_success.html"));
auth.Completed += (sender, eventArgs) =>
{
if (eventArgs.IsAuthenticated)
{
// Authenticated
}
else
{
// The user cancelled
}
};
activity.StartActivity(auth.GetUI(activity));
}
}
}
}
Exception appears on auth.Completed event
Stack Trace: at Dating.Droid.Renderers.FirstPageRenderer+<>c.<.ctor>b__0_0 (System.Object sender, Xamarin.Auth.AuthenticatorCompletedEventArgs eventArgs) [0x00002] in D:\Dev\Real\Xamarin\Dating\Dating.Droid\Renderers\FirstPageRenderer.cs:31

Authenticate with OneDrive SDK in Xamarin Android App

I use the onedrive SDK in a Cross Plattform app. On Windows the Authentication works via the OneDriveClientExtensions.GetClientUsingWebAuthenticationBroker.
Now I'm trying to login on Android. I tried it with this:
oneDriveClient = OneDriveClient.GetMicrosoftAccountClient(
appId: MSA_CLIENT_ID,
returnUrl: RETURN_URL,
scopes: scopes,
clientSecret: MSA_CLIENT_SECRET);
await oneDriveClient.AuthenticateAsync();
But get an error that no valid token could be received. Do I have to implement a own AuthenticationProvider inhereting from WebAuthenticationBrokerAuthenticationProvider who shows a browser for the oauth? Or what would be the way to go here?
I solved this using the Xamarin Auth Component. Heres the code who calls the webview with the login:
private const string RETURN_URL = #"https://login.live.com/oauth20_desktop.srf";
private void ShowWebView()
{
var auth = new OAuth2Authenticator(
clientId: MSA_CLIENT_ID,
scope: string.Join(",", scopes),
authorizeUrl: new Uri(GetAuthorizeUrl()),
redirectUrl: new Uri(RETURN_URL));
auth.Completed += (sender, eventArgs) =>
{
if (eventArgs.IsAuthenticated)
{
//Do Something
}
};
var intent = auth.GetUI(Application.Context);
intent.SetFlags(ActivityFlags.NewTask);
Application.Context.StartActivity(intent);
}
private string GetAuthorizeUrl()
{
var requestUriStringBuilder = new StringBuilder();
requestUriStringBuilder.Append("https://login.live.com/oauth20_authorize.srf");
requestUriStringBuilder.AppendFormat("?{0}={1}", Constants.Authentication.RedirectUriKeyName, RETURN_URL);
requestUriStringBuilder.AppendFormat("&{0}={1}", Constants.Authentication.ClientIdKeyName, MSA_CLIENT_ID);
requestUriStringBuilder.AppendFormat("&{0}={1}", Constants.Authentication.ScopeKeyName,
string.Join("%20", scopes));
requestUriStringBuilder.AppendFormat("&{0}={1}", Constants.Authentication.ResponseTypeKeyName,
Constants.Authentication.TokenResponseTypeValueName);
return requestUriStringBuilder.ToString();
}

Categories

Resources