3

I have added a WebAuthenticator.AuthenticateAsync method in my xamarin forms app with start up Url as "https://accounts.google.com/o/oauth2/auth" and call back url as "myapp://"

I have also tried with call back url as "com.googleusercontent.apps.{clientId}:/oauth2redirect" I am doing this to add google login in my xamarin forms app. On this browser with available google accounts are been showing up and after successful completion of email authentication it returns to app but result is not returned from WebAuthenticator.AuthenticateAsync method. On second time invocation of this method returns the first invocation result as cancelled by user and the browser opens again for second time email authentication.

But it works in ios.

I have added 3 classes

public class Auth0Client
{
    private readonly OidcClient oidcClient;

    public Auth0Client(Auth0ClientOptions options)
    {
        var discovery = new DiscoveryPolicy
        {
            ValidateEndpoints = false,
            Authority = "https://accounts.google.com"
        };
        oidcClient = new OidcClient(new OidcClientOptions
        {
            Authority = $"https://accounts.google.com/o/oauth2/auth",
            ClientId = options.ClientId,
            Scope = options.Scope,
            RedirectUri = options.RedirectUri,
            Browser = options.Browser,
            ProviderInformation = options.ProviderInformation,
            Policy = new Policy
            {
                Discovery = discovery,
                RequireAccessTokenHash = false
            },
        });
    }

    public IdentityModel.OidcClient.Browser.IBrowser Browser
    {
        get
        {
            return oidcClient.Options.Browser;
        }
        set
        {
            oidcClient.Options.Browser = value;
        }
    }

    public async Task<LoginResult> LoginAsync()
    {
        return await oidcClient.LoginAsync();
    }
}
public class Auth0ClientOptions
{
    public Auth0ClientOptions()
    {
        
    }

    public string Domain { get; set; }

    public string ClientId { get; set; }

    public string RedirectUri { get; set; }

    public string Scope { get; set; }

    public IBrowser Browser { get; set; }
    public ProviderInformation ProviderInformation { get; set; }
}

public class WebBrowserAuthenticator : IBrowser
{
    public async Task<BrowserResult> InvokeAsync(BrowserOptions options, CancellationToken cancellationToken = default)
    {
        try
        {
            WebAuthenticatorResult result =  await WebAuthenticator.AuthenticateAsync(
                new Uri(options.StartUrl),new Uri(options.EndUrl));

            var url = new RequestUrl(options.EndUrl)
                .Create(new Parameters(result.Properties));

            return new BrowserResult
            {
                Response = url,
                ResultType = BrowserResultType.Success
            };
        }
        catch (Exception ex)
        {
            return new BrowserResult
            {
                ResultType = BrowserResultType.UserCancel,
                ErrorDescription = "Login canceled by the user."
            };
        }
    }
}

In view model we are creating authoclient

private async void NavigateToGoogleLogin(object obj)
    {
        string clientId = null;
        string redirectUri = null;

        switch (Device.RuntimePlatform)
        {
            case Device.iOS:
                clientId = AppConstants.GoogleiOSClientId;
                redirectUri = AppConstants.GoogleiOSRedirectUrl;
                break;

            case Device.Android:
                clientId = AppConstants.GoogleAndroidClientId;
                redirectUri = AppConstants.GoogleAndroidRedirectUrl;
                break;
        }
        var auth0client = new Auth0Client(new Auth0ClientOptions()
        {
            Domain = "accounts.google.com/o/oauth2/auth",
            ClientId = clientId,
            RedirectUri = redirectUri,
            Scope = AppConstants.GoogleScope,
            Browser = new WebBrowserAuthenticator(),
            ProviderInformation = new ProviderInformation
            {
                IssuerName = "accounts.google.com",
                AuthorizeEndpoint = AppConstants.GoogleAuthorizeUrl,
                TokenEndpoint = AppConstants.GoogleAccessTokenUrl,
                UserInfoEndpoint = AppConstants.GoogleUserInfoUrl,

                KeySet = new JsonWebKeySet(),
            },
        });

        var loginResult = await auth0client.LoginAsync();
    }

We are using below constants in authoclient object creation

internal static string GoogleScope = "https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile";

internal static string GoogleAuthorizeUrl = "https://accounts.google.com/o/oauth2/auth";

internal static string GoogleAccessTokenUrl = "https://www.googleapis.com/oauth2/v4/token";

internal static string GoogleUserInfoUrl = "https://www.googleapis.com/oauth2/v3/userinfo";

Xamarin forms version:5.0.0.2012 Xamarin essentials: 1.7.3

Thanks in advance

  • Do you [use the Intent Filter](https://learn.microsoft.com/en-us/xamarin/essentials/web-authenticator?tabs=android#:~:text=Android%20requires%20an%20Intent%20Filter%20setup%20to%20handle%20your%20callback%20URI.%20This%20is%20easily%20accomplished%20by%20subclassing%20the%20WebAuthenticatorCallbackActivity%20class%3A) setting for your callback URI in Android? – Zack Dec 06 '22 at 06:46
  • yes I have used like below. [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 = "com.googleusercontent.apps.{androidClient id}", DataHost= "/oauth2redirect")] public class WebAuthenticationCallbackActivity : Xamarin.Essentials.WebAuthenticatorCallbackActivity { } – Sushmitha Rao B Dec 06 '22 at 07:43
  • I have added this in andorid manifest @DongzhiWang-MSFT – Sushmitha Rao B Dec 06 '22 at 07:46
  • You can try to change `DataScheme = "com.googleusercontent.apps.{androidClient id}", DataHost="/oauth2redirect"` to `DataScheme="myapp"`, make a breakpoint in the code to track and check whether the callback is normal run. Can you provide some code where you use WebAuthenticator.AuthenticateAsync? – Zack Dec 06 '22 at 09:53
  • We have tried with "myapp" in datascheme too. But no progress. Am following this maui blog https://auth0.com/blog/add-authentication-to-dotnet-maui-apps-with-auth0/ Instead of maui web authenticator we are using xamarin essentials web authenticator. @DongzhiWang-MSFT – Sushmitha Rao B Dec 06 '22 at 10:26
  • I have also added the code in the question section @DongzhiWang-MSFT – Sushmitha Rao B Dec 06 '22 at 10:48
  • You said: "returns the first invocation result as canceled by user". However, by looking at your code, I found that this is the error description in your `catch` which indicates that there is an error in your `try` statement. You can try to run the code without a `try...catch` block and add a breakpoint in the code to see the error message. – Zack Dec 07 '22 at 09:51
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/250219/discussion-between-sushmitha-rao-b-and-dongzhi-wang-msft). – Sushmitha Rao B Dec 07 '22 at 10:25
  • okay, I posted a message in chat. – Zack Dec 09 '22 at 01:45
  • Experiencing same issue here . Did you ever figure thie out ? – James Wilkinson Feb 01 '23 at 07:22
  • @JamesWilkinson Please try by adding protected async override void OnNewIntent(Intent intent) { base.OnNewIntent(intent); } in mainactivity [Activity(NoHistory = true, LaunchMode = LaunchMode.SingleTask, Exported = true)] [IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault, Intent.CategoryBrowsable }, DataSchemes = new[] { "your value" }, DataPath = "Your value", DataPathPrefix = "your value")] – Sushmitha Rao B Feb 14 '23 at 04:47

0 Answers0