CR41G14
CR41G14

Reputation: 5594

Serious OAuth issue with MVC4

I am having an issue with OAuth and Facebook. I am using MVC4 standard OAuth login. I am not having the issue locally but on the server this is proving to be a problem.

If I paste the following URL into the browser it works OK:

http://localhost:46260/Account/ExternalLoginCallback?ReturnUrl=%2FDashboard&__provider__=FacebookPro&__sid__=1234somesid456  // this is autogenerated

When I change the URL for the app in facebook to the current domain and paste this url in, I get re-directed to the Unsuccessful login page:

http://freersvp.mytakeawaysite.com:80/Account/ExternalLoginCallback?ReturnUrl=%2FDashboard&__provider__=Facebook+Pro&__sid__=1234someid456  // note this is autogenerated

N.B The above two url's are the redirect uri

The below URL is what is requested and is causing the exception:

URL

https://graph.facebook.com/oauth/access_token?client_id=52*********37&redirect_uri=http%3a%2f%2ffreersvp.mytakeawaysite.com%3a80%2fAccount%2fExternalLoginCallback%3fReturnUrl%3d%252FDashboard%26__provider__%3dFacebook%2bPro%26__sid__%3d3c92eb7e84304afc931ef0ea7b62f56a&client_secret=2123***********4256&code=AQAQIJsj-ondldllVYKdpxJaZouqrlg9sjTcfUxyWhAw8MXbD2DvsOSujg2m7E3s3cvNusCI0ZZoJAuGgu_FLkPyjYMQAkTWDVyHTcAoJD-tezyXgn0vhoFzX3FmuRBHYpyJEM-dk0KgF5ugsTHo9yGjBjrcfMDUGu9IxkKQ36k3gMrwocM1_l5t342Q2kIOHdt8pPcyrs--NzgNyZv48vSq7jkZwuQ95xRjUHG5J-ptcgq0l2BlqjzHDDuvIFH23lpMWHzzqdejdj5ejukz7t_Fnhx-mrpVdcRYhP3JeZ2UOTjAyKQmUB3rInooECcjq4c

Exception

  {
       "error": {
          "message": "Error validating verification code. Please make sure your redirect_uri is identical to the one you used in the OAuth dialog request",
          "type": "OAuthException",
          "code": 100
       }
    }

The string token does come back with null in the GetUserData function in the below code:

I am using the FacebookScopedClient:

public class FacebookScopedClient : IAuthenticationClient
{
    private string appId;
    private string appSecret;
    private string scope;

    private const string baseUrl = "https://www.facebook.com/dialog/oauth?client_id=";
    public const string graphApiToken = "https://graph.facebook.com/oauth/access_token?";
    public const string graphApiMe = "https://graph.facebook.com/me?";

    private static string GetHTML(string URL)
    {
        string connectionString = URL;

        try
        {
            System.Net.HttpWebRequest myRequest = (HttpWebRequest)WebRequest.Create(connectionString);
            myRequest.Credentials = CredentialCache.DefaultCredentials;
            //// Get the response
            WebResponse webResponse = myRequest.GetResponse();
            Stream respStream = webResponse.GetResponseStream();
            ////
            StreamReader ioStream = new StreamReader(respStream);
            string pageContent = ioStream.ReadToEnd();
            //// Close streams
            ioStream.Close();
            respStream.Close();
            return pageContent;
        }
        catch(Exception ex)
        {
        }
        return null;
    }

    private IDictionary<string, string> GetUserData(string accessCode, string redirectURI)
    {
        SessionControl ctl = new SessionControl();
        ctl.SaveParam("redirecturi", redirectURI, -3);
        ctl.Dispose();
        string token = GetHTML(graphApiToken + "client_id=" + appId + "&redirect_uri=" + HttpUtility.UrlEncode(redirectURI) + "&client_secret=" + appSecret + "&code=" + accessCode);

        if(token == null || token == "")
        {

            return null;
        }
        string access_token = token.Substring(token.IndexOf("access_token="), token.IndexOf("&"));
        string data = GetHTML(graphApiMe + "fields=id,name,email,username,gender,link&" + access_token);

        try
        {


        }
        catch { }
        // this dictionary must contains
        Dictionary<string, string> userData = JsonConvert.DeserializeObject<Dictionary<string, string>>(data);
        userData.Add("accesstoken", access_token);

        try
        {
            userData.Add("id", userData["id"]);
        }
        catch { }
        return userData;
    }

    public FacebookScopedClient(string appId, string appSecret, string scope)
    {
        this.appId = appId;
        this.appSecret = appSecret;
        this.scope = scope;
    }

    public string ProviderName
    {
        get { return "FacebookPro"; }
    }

    public void RequestAuthentication(System.Web.HttpContextBase context, Uri returnUrl)
    {
        string url = baseUrl + appId + "&redirect_uri=" + HttpUtility.UrlEncode(returnUrl.ToString()) + "&scope=" + scope;
        context.Response.Redirect(url);
    }

    public AuthenticationResult VerifyAuthentication(System.Web.HttpContextBase context)
    {
        string code = context.Request.QueryString["code"];

        string rawUrl = context.Request.Url.OriginalString;
        //From this we need to remove code portion
        rawUrl = Regex.Replace(rawUrl, "&code=[^&]*", "");

        IDictionary<string, string> userData = GetUserData(code, rawUrl);

        if(userData == null)
            return new AuthenticationResult(false, ProviderName, null, null, null);

        string id = userData["id"];


        string username = userData["email"];

        if(username == null || username == "")
        {
            username = userData["username"];
        }
        //userData.Remove("id");
        userData.Remove("username");

        AuthenticationResult result = new AuthenticationResult(true, ProviderName, id, username, userData);
        return result;
    }
}

Upvotes: 3

Views: 780

Answers (3)

Jacqueline Loriault
Jacqueline Loriault

Reputation: 690

after running your posted url that's causing the error through a url decoder the issue lies in for some reason your url encoding the entire query string and not just the url.

you will notice in that url a bunch of %26 items those are url encoded & and that's what is throwing your error. the Facebook parser is seeing %26 instead of & and treating it as one single parameter.

the & separates url query string parameters when sending to a page. Without the full code I can't tell you where to look but some where in your code your completely encoding the entire query string and need to find that piece of code and only encode the embedded urls.

ok after reading over things maybe try this theory.

I think your code is receiving this stuff from Facebook, url encoded, and then your system is re-encoding it. try taking anything received and first url decode it, manipulate it and then re-encode things as needed.

hope this helps

Upvotes: 3

Deep
Deep

Reputation: 54

Try it with sandbox mode off within facebook app.

Upvotes: 0

Pedro Matos
Pedro Matos

Reputation: 387

Noticing your URL's query string, I found an answer from Stackoverflow. Please see if it solves your issue: https://stackoverflow.com/a/16699058/2005136

Steve S posted as a response:

"In our case, we were doing something unusual (so this might not be relevant to your case). Our redirect_uri was a URL with another URL embedded as an encoded path element. The URL-within-a-URL, doubly-encoded when passed to FB, had started causing problems with the Facebook API servers.

We resolved this by changing the encoding of the nested URL to a long hex number rather than % encoding, so all Facebook servers see is a simple redirect_uri containing some hex within the path, unaffected by normal URL encoding/decoding."

Upvotes: -1

Related Questions