Search code examples
c#parse-platformauthenticationxamarintwitter-oauth

Logging with Twitter c# implementation on parse.com


In my application i want users to be able to login with facebook and twitter.
For facebook i see there is a procedure ready for that ParseFacebookUtils but there isn't anything like that for Twitter so im making my own.
I have create an implementation for logging in with twitter:

void  LoginToTwitter ()
    {
        var auth = new OAuth1Authenticator(
            "<authkey>",
            "<authsecret>",
            new Uri("https://api.twitter.com/oauth/request_token"),
            new Uri("https://api.twitter.com/oauth/authorize"),
            new Uri("https://api.twitter.com/oauth/access_token"),
            new Uri("http://twitter.com/"));

        auth.Completed += GetTwitterData;

        var ui = auth.GetUI(Activity);
        StartActivity(ui);
    }

    async public void GetTwitterData( object sender, AuthenticatorCompletedEventArgs e )
    {
        var request = new OAuth1Request(
            "GET",
            new Uri("https://api.twitter.com/1.1/account/verify_credentials.json "),
            null,
            e.Account);

        await request.GetResponseAsync().ContinueWith(t =>
            {
                var res = t.Result;
                var resString = res.GetResponseText();
                Console.WriteLine("Result Text: " + resString);
                var jo = Newtonsoft.Json.Linq.JObject.Parse(resString);
                var imageUrl = new Java.Net.URL((string)jo["profile_image_url"]);
                var twitterId = jo["id"];
                var accessToken = e.Account.Properties["access_token"].ToString();
                var expiresIn = Convert.ToDouble(e.Account.Properties["expires_in"]);
                var expiryDate = DateTime.Now + TimeSpan.FromSeconds( expiresIn );
                var userRealName = e.Account.Properties["screen_name"];
            }, UIScheduler);
    }

And now the only thing left is to associate there data With a new user or if the user exist to logg him in.
I see ParseFacebookUtils creates a randomly username for each user. In order for me to do something like that i must first check if the random generated username doesn't already exist, is it a good idea to use twitter username for that? Also facebook stores something called authData of type authData with content like this:

{"facebook":    {"access_token":"some_token","expiration_date":"some_date","id":"some_id"}}

How i can create something like that for twitter? i have already generate the required fields


Solution

  • I have successfully Login with twitter on Xamarin.Android with Parse.com

    Here is how i manage to do it in case is useful to someone else, you will need components Xamarin.auth and RestSharp:

    void  LoginToTwitter ()
        {
            var auth = new OAuth1Authenticator(
                "some_key",
                "some_key",
                new Uri("https://api.twitter.com/oauth/request_token"),
                new Uri("https://api.twitter.com/oauth/authorize"),
                new Uri("https://api.twitter.com/oauth/access_token"),
                new Uri("https://mobile.twitter.com/"));
    
            //save the account data in the authorization completed even handler
            auth.Completed += GetTwitterData;
    
            var ui = auth.GetUI(Activity);
            StartActivity(ui);
        }
    
        public async void GetTwitterData( object sender, AuthenticatorCompletedEventArgs e )
        {
            //use the account object and make the desired API call
            if (e.IsAuthenticated)
                Console.WriteLine("Logged in");
    
            var request = new OAuth1Request(
                "GET",
                new Uri("https://api.twitter.com/1.1/account/verify_credentials.json"),
                null,
                e.Account, true);
    
            await request.GetResponseAsync().ContinueWith(t =>
                {
                    if (!t.IsFaulted && !t.IsCanceled){
                    var res = t.Result;
                    var resString = res.GetResponseText();
                    //Console.WriteLine("Result Text: " + resString);
                    var jo = Newtonsoft.Json.Linq.JObject.Parse(resString);
                    imageUrl = new Java.Net.URL((string)jo["profile_image_url"]);
                    var twitterId = jo["id"];
    
                    }
    
                }, UIScheduler);
    
            var userID = e.Account.Properties["user_id"];
            var name = e.Account.Properties["screen_name"];
    
            var oauth_consumer_key = e.Account.Properties["oauth_consumer_key"];
            var oauth_consumer_secret = e.Account.Properties["oauth_consumer_secret"];
            var oauth_token = e.Account.Properties["oauth_token"];
            var oauth_token_secret = e.Account.Properties["oauth_token_secret"];
    
            var authData = new Dictionary<string,string>();
            authData.Add("user_id",userID.ToString());
            authData.Add("screen_name",name.ToString());
            authData.Add("oauth_consumer_key",oauth_consumer_key.ToString());
            authData.Add("oauth_consumer_secret",oauth_consumer_secret.ToString());
            authData.Add("oauth_token",oauth_token.ToString());
            authData.Add("oauth_token_secret",oauth_token_secret.ToString());
            await ParseLoginOrCreate(authData);
        }
    
        public async Task<ParseUser> ParseLoginOrCreate(Dictionary<string,string> authInfo) 
        {
            var rest = new RestSharp.RestClient ("https://api.parse.com");
            var req = new RestSharp.RestRequest ("1/users/", RestSharp.Method.POST);
            req.AddHeader ("X-Parse-Application-Id", "some_key");
            req.AddHeader ("X-Parse-REST-API-Key", "some_key");
            req.AddHeader ("Content-Type", "application/json");
    
            var payload = "{ \"authData\": { \"twitter\": { ";
            payload += "\"id\": \"" + authInfo["user_id"] + "\", ";
            payload += "\"screen_name\": \"" + authInfo["screen_name"] + "\", ";
            payload += "\"consumer_key\": \"" + authInfo["oauth_consumer_key"] + "\", ";
            payload += "\"consumer_secret\": \"" + authInfo["oauth_consumer_secret"] + "\", ";
            payload += "\"auth_token\": \"" + authInfo["oauth_token"] + "\", ";
            payload += "\"auth_token_secret\": \"" + authInfo["oauth_token_secret"] + "\" ";
            payload += "} } }";
    
            req.AddParameter("application/json", payload, RestSharp.ParameterType.RequestBody);
    
            RestSharp.IRestResponse res = null;
            var result = await Task<JContainer>.Run(()=>{
                res = rest.Execute(req);
                var content = res.Content;
                return JsonConvert.DeserializeObject<Newtonsoft.Json.Linq.JContainer>(content);
            });
            var sessionToken = (String)result["sessionToken"];
            var objectId = (String)result["objectId"];
    
            if (res.StatusCode == System.Net.HttpStatusCode.Created)
            {
                req = new RestSharp.RestRequest ("1/users/" + objectId, RestSharp.Method.PUT);
                req.AddHeader ("X-Parse-Application-Id", "some_key");
                req.AddHeader ("X-Parse-REST-API-Key", "some_key");
                req.AddHeader ("X-Parse-Session-Token", sessionToken);
                req.AddHeader ("Content-Type", "application/json");
    
                req.AddParameter("application/json", "{ \"username\": \"" + authInfo["screen_name"] + "\" }", RestSharp.ParameterType.RequestBody);
                result = await Task<JContainer>.Run(() => {
                    res= rest.Execute(req);
                    var content = res.Content;
                    return JsonConvert.DeserializeObject<Newtonsoft.Json.Linq.JContainer>(content);
                });
            }
    
            await ParseUser.BecomeAsync (sessionToken);
    
            return ParseUser.CurrentUser;
        }