Search code examples
c#facebookauthenticationwindows-store-apps

Facebook authentication (OAuth2) from Windows Store App (WebAuthenticationBroker.AuthenticateAsync) fails on desktop computers


I have a published Xamarin.Forms app. The app suggests users to authenticate via several OAuth authentication providers (Google, Facebook, Microsoft, Yandex, Vkontakte, Mail.Ru, Odnoklassniki).

On Windows the authentication via Facebook is built in the following way:

string clientID = "<client ID from facebook app settings>";

string startUri = "https://m.facebook.com/dialog/oauth/?" + 
    "client_id=" + clientID +
    "&scope=" + "email,public_profile" + 
    "&redirect_uri=" + "https://m.facebook.com/connect/login_success.html" + 
    "&state=" + Guid.NewGuid().ToString("N") + 
    "&response_type=" + "token";

WebAuthenticationBroker.AuthenticateAsync(
    WebAuthenticationOptions.None,
    new Uri(startUri),
    new Uri("https://m.facebook.com/connect/login_success.html"));

The same schematics but with different Uris is used for other authentication providers and works fine. Facebook authentication works on windows phones but fails on Windows 10 and Windows 8.1 desktop computers. The failure scenario:

  1. The WebAuthenticationBroker windows appears. The WebAuthenticationBroker windows appears

  2. The facebook authentication dialog content appears for a couple of seconds. The facebook authentication dialog content appears for a couple of seconds

  3. The facebook authentication dialog content disappears and the following text appears instead: "We can't connect to the service you need right now. Check your network connection or try this again later.". We can't connect to the service you need right now. Check your network connection or try this again later.

Between the steps 2 and 3 none of my app code is executing. The same happens on many different computers. I tried replacing the Uri from m.facebook.com to www.facebook.com to no effect.

The Task<WebAuthenticationResult> returned from WebAuthenticationBroker.AuthenticateAsync finishes with the IsFaulted state and the following exception inside:

System.AggregateException: One or more errors occurred. ---> System.Exception: Exception from HRESULT: 0x800C0503

--- End of inner exception stack trace ---

---> (Inner Exception #0) System.Exception: Exception from HRESULT: 0x800C0503<---

Where should I dig further?


Solution

  • I've been working closely with Facebook SDK support and Microsoft support on the issue. This is much like to be banged from two sides simultaneously while trying to be pleasant to yourself in the same time. Feeling myself spoiled and wasted yet satisfied.

    Long story short I have a workaround which I now use just for the Facebook/Windows desktop combo:

    //We need to instruct the WebAuthenticationBroker to end the scenario
    //somehow without specifying the callbackUri parameter. This is called 
    //`an implicit callback Uri scenario` in which WebAuthenticationBroker
    //is expecting to see this Uri for the end:
    string callbackUri = WebAuthenticationBroker.GetCurrentApplicationCallbackUri().AbsoluteUri;
    
    //So we need to instruct Facebook authentication to finally redirect to this Uri.
    string startUri = "https://m.facebook.com/dialog/oauth/?" + 
        "client_id=" + clientID +
        "&scope=" + "email,public_profile" + 
        "&redirect_uri=" + callbackUri + 
        "&state=" + Guid.NewGuid().ToString("N") + 
        "&response_type=" + "token";
    
    //The workaround is to go with the WebAuthenticationBroker.AuthenticateAsync
    //overload which does not accept the callbackUri parameter.
    WebAuthenticationBroker.AuthenticateAsync(
        WebAuthenticationOptions.None,
        new Uri(startUri)));
    

    Neither Facebook nor Microsoft did a thing to be helpful in getting around this or provide any logical explanation on why this scenario has to be used for Windows desktop. I mention that again: on Windows Phone 8.1 / 10 the explicit callback Uri scenario works perfectly.

    I have to mention that in order for such an implicit callback Uri to be accepted by Facebook authentication you need to include these Uris into the Valid OAuth redirect URIs setting of Facebook login parameters for your app.

    1. https://www.facebook.com/dialog/return/ms
    2. https://m.facebook.com/dialog/return/ms

    ...another design masterpiece by Facebook. Argh.