Search code examples
facebookasp.net-web-apixamarinowinfacebook-graph-api-v2.0

WebAPI Facebook login returning Access Denied when removing permissions


I have a client app (written with Xamarin) for iOS and WP which uses a WebAPI with Facebook as the sole method of logging in. My issue is that when a user customises the required permissions and removes some of them, the WebAPI simply receives "access_denied" from either OWIN or Facebook (externally to my code).

The app is also added to their Facebook account with the subset of restricted permissions they chose, which means on every subsequent login they also get "access denied". Also, because they did not successfully register with the WebAPI, I do not have a user access token for facebook so that I can remove the app from their Facebook account (to start again). The only way to fix this issue is to manually visit facebook and remove the app from your app settings page, then try again.

I am completely stuck. When logging in, they enter the following method at the WebAPI and reach the return on ChallengeResult();

    [Route("ExternalLogin", Name = "ExternalLogin")]
    public async Task<IHttpActionResult> GetExternalLogin(string provider, string error = null)
    {
        if (error != null)
        {
            return Redirect(Url.Content("~/") + "#error=" + Uri.EscapeDataString(error));
        }

        if (!User.Identity.IsAuthenticated)
        {
            return new ChallengeResult(provider, this);
        }

From here, it communicates (authenticates) with Facebook and the subsequent call to this method returns on Redirect() with "access denied" as the error.

I believe (but am not sure) that this is happening because my WebAPI is trying to log them in with the full set of permissions, but Facebook is saying no, they have your app listed with only 1 permission, so "access denied" is returned. My Startup.auth.cs file looks like this;

        var facebookOptions = new Microsoft.Owin.Security.Facebook.FacebookAuthenticationOptions
        {
            AppId = Constants.AppId,
            AppSecret = Constants.AppSecret,
            Provider = new FacebookAuthenticationProvider()
            {
                OnAuthenticated = (context) =>
                {
                    context.Identity.AddClaim(new System.Security.Claims.Claim("urn:facebook:access_token", context.AccessToken, ClaimValueTypes.String, "Facebook"));
                    context.Identity.AddClaim(new System.Security.Claims.Claim("urn:facebook:email", context.Email, ClaimValueTypes.Email, "Facebook"));
                    return Task.FromResult(0);
                }
            },
        };
        facebookOptions.Scope.Add("email");
        facebookOptions.Scope.Add("user_friends");
        app.UseFacebookAuthentication(facebookOptions);

How am I supposed to manage the situation when a user removes some of the default permissions on their first log in? I would expect that they could successfully register with my WebAPI, but then any call for the permissions they did not allow would fail, but this is not happening. I am simply presented with the "access denied" on log in.

Any help would be amazing because I am totally stuck here!


Solution

  • Found it...

    In the OnAuthenticated method in Startup.auth.cs, you have access to the USER access token. Here you can check facebook permissions granted by accessing the graph api with the token, and remove the app if needed.

    The method was failing because context.email was null;

    context.Identity.AddClaim(new System.Security.Claims.Claim("urn:facebook:email", context.Email, ClaimValueTypes.Email, "Facebook"));