Search code examples
asp.net-corexamarin.formsgoogle-oauth

You must subclass the WebAuthenticatorCallbackActivity and create an IntentFilter for it which matches your callbackUrl


I am building a Xamarin Forms application with Google Authentication via OAuth2. There are quite a few examples of integrating Google Authentication into Xamarin forms but most of these posts appear outdated.

The most recent instruction from Microsoft is to use Xamarin Essentials based on this MSDN post. Microsoft's advice is to leverage a web backend to proxy the request to the third-party identity provider. In this case, I will be using an ASP.NET Core backend.

Within the Google cloud console, I have configured the redirect url of the OAuth web application to point to my deployed service instance in the cloud. This url is:

https://my-google-app.appspot.com/signin-google

Assuming my ASP.NET Core app is exposed at base url https://my-google-app.appspot.com.

In MobileAuthController, that provides the authentication URL for the application, copied from this Github repo, the callback scheme is supposed to be the URL registered in my app for deep linking as per my understanding of the flow so far:

someappname://abc

assuming the package name of my Android application is com.my-app-package-name. This all appears or sounds reasonable.

Somewhere in the mobile application, I am initiating the authentication request using the Xamarin Essentials package as follows:

var result = await WebAuthenticator.AuthenticateAsync(
            new Uri("https://my-google-app.appspot.com/mobileauth/Google"),
            new Uri("someappname://abc"));

In my Android project, I have an intent filter defined as follows:

[Activity(NoHistory = true, LaunchMode = LaunchMode.SingleTop, Exported = true)]
    [IntentFilter(new []{Android.Content.Intent.ActionView},
        Categories = new[] {Android.Content.Intent.CategoryDefault, Android.Content.Intent.CategoryBrowsable},
        DataPath ="abc",
        DataSchemes = new[]
            {
                "someappname"  /* package id */
            })
    ]

    public class WebAuthenticationCallbackActivity : Xamarin.Essentials.WebAuthenticatorCallbackActivity
    {
    }
}

So far, so good :). However, when I run the application, I get the error:

System.InvalidOperationException: 'You must subclass the WebAuthenticatorCallbackActivity and create an IntentFilter for it which matches your callbackUrl.

I have not been able to make sense of that error as Google will to redirect to my deployed ASP.NET instance which would then redirect to my app from my understanding.

UPDATE:

Correct my callback URL and problem persists.


Solution

  • This specific issue was being caused by a trailing slash in my redirect URL causing a mismatch between what I thought I was sending vs what the Xamarin app was constructing.

    I ended up defining my redirect url as

    someappname://callback/
    

    The trailing slash ensures I can guarantee the same Uri being constructed on the Android intent which I then defined as follows:

    [Activity(NoHistory = true, LaunchMode = LaunchMode.SingleTop, Exported = true)]
        [IntentFilter(new []{Android.Content.Intent.ActionView},
            Categories = new[] {Android.Content.Intent.CategoryDefault, Android.Content.Intent.CategoryBrowsable},
    
            // need to ensure we have a backslash 
            DataPath = "/callback/", 
            DataScheme = "someappname")
        ]
    
        public class WebAuthenticationCallbackActivity : Xamarin.Essentials.WebAuthenticatorCallbackActivity
        {
            
        }
    

    The c# Uri class will append a trailing slash at the end of your custom scheme if defined without a trailing slash and this would cause confusion as you do not expect this. The MSDN docs is not clear on this.