Windows Phone 8 - Twitter API - c#

I am doing some research and can't seem to find a definitive way to query Twitter's API to get a user's tweets on WP8 using C#.
The twitter user isn't my own account and all I want to do is retrieve tweets and not post any tweets.
Do I therefore need to Authenticate myself/my app? Is the TweetSharp library appropriate for my objective?

I used the following example http://code.msdn.microsoft.com/wpapps/Twitter-Sample-using-f36bab75:
if (NetworkInterface.GetIsNetworkAvailable())
{
//Obtain keys by registering your app on https://dev.twitter.com/apps
var service = new TwitterService("abc", "abc");
service.AuthenticateWith("abc", "abc");
//ScreenName is the profile name of the twitter user.
service.ListTweetsOnUserTimeline(new ListTweetsOnUserTimelineOptions() { ScreenName = "the_appfactory" }, (ts, rep) =>
{
if (rep.StatusCode == HttpStatusCode.OK)
{
//bind
this.Dispatcher.BeginInvoke(() => { tweetList.ItemsSource = ts; });
}
});
}
else
{
MessageBox.Show("Please check your internet connestion.");
}
I created a new application user the twitter dev website: https://dev.twitter.com/user/login?destination=home. Once this was set-up, I essentially copied and pasted the keys within the AuthenticateWith and TwitterService methods.
I haven't solved exactly how I shall display the data but, at runtime, I can see data being passed in.

Related

Adding Google API Offline access to a .NET Core app

I've written an ASP.NET Core webapp that uses Auth0 as its primary authorization mechanism for users, which middlemans a whole bunch of external auth endpoints like Google and Facebook. That works fine and I have no issues there.
At its core the webapp makes use of Google Analytics to perform its own analytics and business logic. The Google Analytics account that is being analysed by my webapp could and is likely different from the users' own Google account. To be clear what I mean is that it is likely the user will login with whatever login provider they wish, and then they'll attach a specific Google business account with access to their businesses Google Analytics system.
The webapp performs analytics both whilst the user is logged in, and whilst the user is offline.
So I've always kept the user auth (Auth0) step seperate from the auth of the Analytics account step. The general process is as follows:
User logs in via Auth0 using whatever provider (Google, Facebook, email/pass) and accesses the private dashboard.
User sets up a "Company" and clicks on a button to authorize our webapp access to a specific Google account with Analytics on it.
User is redirected back to the private dashboard and the refresh token of the Google account is stored for future use.
Previously I had been pushing the Analytics auth through Auth0 as well, and I used a cached Auth0 refresh token to do work offline. However it expires after some days and Auth0 don't appear to provide long-term offline access.
So I figure the easiest thing to do would be to simply not use auth0 for the Analytics auth step, auth directly with the Google API and store the Google refresh token long-term. However I cannot find any concrete examples of how to achieve this!
Official Google API .NET Example - This appears to be very old and not really supported by ASPNET Core. I can't see a clear way to mould this into anything usable and searching SO finds clear issues with it.
SO answer to a similar question - It's a great answer, but the implementation is for user auth and I don't believe would work in my scenario.
I finally cracked it! I ended up throwing away all the libraries and found that it was simplest to use the plain old REST API. Code example below for those curious:
The users' browser GETs the following and is redirected to Google for an auth token:
public IActionResult OnGet([FromQuery]int id, [FromQuery]string returnAction)
{
var org = context.Organizations.Include(o => o.UserOrgs).First(o => o.Id == id);
var user = GetUser();
if (!IsUserMemberOfOrg(user, org)) return BadRequest("User is not a member of this organization!");
var redirectUri = Uri.EscapeUriString(GetBaseUri()+"dash/auth/google?handler=ReturnCode");
var uri = $"https://accounts.google.com/o/oauth2/v2/auth?"+
$"scope={Uri.EscapeUriString("https://www.googleapis.com/auth/analytics.readonly")}"+
$"&prompt=consent"+
$"&access_type=offline"+
//$"&include_granted_scopes=true"+
$"&state={Uri.EscapeUriString(JsonConvert.SerializeObject(new AuthState() { OrgId = id, ReturnAction = returnAction }))}"+
$"&redirect_uri={redirectUri}"+
$"&response_type=code"+
$"&client_id={_configuration["Authentication:Google:ClientId"]}";
return Redirect(uri);
}
Google redirects back to the following, and which point I perform a POST from the webserver to a Google API to exchange the auth token for a refresh token and store it for later:
public async Task<IActionResult> OnGetReturnCode([FromQuery]string state, [FromQuery]string code, [FromQuery]string scope)
{
var authState = JsonConvert.DeserializeObject<AuthState>(state);
var id = authState.OrgId;
var returnAction = authState.ReturnAction;
var org = await context.Organizations.Include(o => o.UserOrgs).SingleOrDefaultAsync(o => o.Id == id);
if (org == null) return BadRequest("This Org doesn't exist!");
using (var httpClient = new HttpClient())
{
var redirectUri = Uri.EscapeUriString(GetBaseUri()+"dash/auth/google?handler=ReturnCode");
var dict = new Dictionary<string, string>
{
{ "code", code },
{ "client_id", _configuration["Authentication:Google:ClientId"] },
{ "client_secret", _configuration["Authentication:Google:ClientSecret"] },
{ "redirect_uri", redirectUri },
{ "grant_type", "authorization_code" }
};
var content = new FormUrlEncodedContent(dict);
var response = await httpClient.PostAsync("https://www.googleapis.com/oauth2/v4/token", content);
var resultContent = JsonConvert.DeserializeObject<GoogleRefreshTokenPostResponse>(await response.Content.ReadAsStringAsync());
org.GoogleAuthRefreshToken = resultContent.refresh_token;
await context.SaveChangesAsync();
return Redirect($"{authState.ReturnAction}/{authState.OrgId}");
}
}
Finally, we can get a new access token with the refresh token later on without user intervention:
public async Task<string> GetGoogleAccessToken(Organization org)
{
if(string.IsNullOrEmpty(org.GoogleAuthRefreshToken))
{
throw new Exception("No refresh token found. " +
"Please visit the organization settings page" +
" to setup your Google account.");
}
using (var httpClient = new HttpClient())
{
var dict = new Dictionary<string, string>
{
{ "client_id", _configuration["Authentication:Google:ClientId"] },
{ "client_secret", _configuration["Authentication:Google:ClientSecret"] },
{ "refresh_token", org.GoogleAuthRefreshToken },
{ "grant_type", "refresh_token" }
};
var resp = await httpClient.PostAsync("https://www.googleapis.com/oauth2/v4/token",
new FormUrlEncodedContent(dict));
if (resp.IsSuccessStatusCode)
{
dynamic returnContent = JObject.Parse(await resp.Content.ReadAsStringAsync());
return returnContent.access_token;
} else
{
throw new Exception(resp.ReasonPhrase);
}
}
}

Google Compute Engine Api using oAuth to list instances c#

Can you please show me some c# example for Authorizing and getting instances using Google Compute engine? When I tried authorizing through some of the code that are out there it is always popping up the gmail login page. Is it necessary to use my own login username or can I use the username of the person who created the vm instances on the google cloud platform?
Can you please show me some c# example for Authorizing and getting instances using Google Compute engine?
The following code can help.
private async Task<List<Instance>> GetAllInstances()
{
List<Instance> instanceResult = new List<Instance>();
var service = assign GooglecomputeServiceObject;
InstancesResource instancesResource = new InstancesResource(service);
InstanceList instanceList = await instancesResource.List(your ProjectId, specify_Zone).ExecuteAsync();
if (instanceList.Items != null)
foreach (var item in instanceList.Items)
{
instanceResult.Add(item);
}
return instanceResult;
}

Implementing External Authentication for Mobile App in ASP.NET WebApi 2

I'm trying to build an API (using ASP.NET WebApi) that will be consumed by a native mobile app for a school project. (I'm not concerned about/developing the mobile app, this responsibility falls on a different member)
I'm at a point where I need to implement a token based Facebook login. There are a lot of tutorials available for how to implement this feature for browser based apps (this is pretty straight forward and most of it comes inbuilt), but I don't think I follow how this would work with native apps. What I don't understand is how the redirects would work?
According to this link, nothing needs to be handled specifically by my server. And I don't think I understand how this would work? How would the tokens from Facebook be handled?
Also, what part of token handling should I implement, I couldn't really find good documentation for WebApi external login authentication.
Anyway, if someone could point me to the exact flow of token exchanges that happen and what is implemented by default by ASP.NET, that would be super helpful.
Also, the biggest point of confusion for me is I don't understand how the token returned by Facebook will be handled.
I assume the token will be returned to the client (mobile app), how do I get access to it on my server?
How do I create a local token from facebook's token?
Is this all done internally/auto-magically by ASP.NET?
I'm sorry if this is something I should've been able to figure out. I did do quite a bit of research and I found myself drowning in (related & unrelated) information. I don't think I even know how to search for the information I need.
Some links I've read:
Claims And Token Based Authentication (ASP.NET Web API)
Token Based Authentication using ASP.NET Web API 2, Owin, and Identity
ASP.NET Web API 2 external logins with Facebook and Google in AngularJS app
I had to do pretty much the same thing for an application I was working on. I also had a lot of trouble finding information about it. It seemed like everything I found was close to what I needed, but not exactly the solution. I ended up taking bits and pieces from a bunch of different blog posts, articles, etc. and putting them all together to get it to work.
I remember two of the links you posted "Claims and Token Based Authentication" and "ASP.NET Web API 2 external logins with Facebook and Google in AngularJS app" as being ones that had useful information.
I can't give you a comprehensive answer since I don't remember everything I had to do, nor did I even understand everything I was doing at the time, but I can give you the general idea. You are on the right track.
Essentially I ended up using the token granted by Facebook to confirm that they were logged into their Facebook account, created a user based on their Facebook user ID, and granted them my own bearer token that they could use to access my API.
The flow looks something like this:
Client authenticates with Facebook via whatever method (we used oauth.io)
Facebook returns them a token
Client sends token information to the registration endpoint of my WebApi controller
The token is validated using Facebook's Graph API, which returns user info
A user is created in the database via ASP.NET Identity with their Facebook user ID as the key
Client sends token information to the authentication endpoint of my WebApi controller
The token is validated using Facebook's Graph API, which returns user info
The user info is used to look up the user in the database, confirm they have previously registered
ASP.NET Identity is used to generate a new token for that user
That token is returned to the client
Client includes an Authorization header in all future HTTP requests with the new token granted by my service (ex. "Authorization: Bearer TOKEN")
If the WebApi endpoint has the [Authorize] attribute, ASP.NET Identity will automatically validate the bearer token and refuse access if it is not valid
There ended up being a lot of custom code for implementing the OAuth stuff with ASP.NET Identity, and those links you included show you some of that. Hopefully this information will help you a little bit, sorry I couldn't help more.
I followed this article. The flow is basically this
The server has the facebook keys just like with web login
The app asks for available social logins and displays buttons (you can hardcode this I guess)
When a button is pressed the app opens a browser and sets the URL to the one related to the specified social login. The ASP.NET then redirects the browser to facebook/google/whatever with the appropriate Challenge
The user might be logged in or not and might have given permission to your app or not. After he gives the permissions facebook redirects back to the provided callback URL
At that point you can get the external login info from the SignInManager and check if the user already exists and if you should create a new account
Finally a token is generated and the browser is redirected to a URL in which the token is placed. The app gets the token from the URL and closes the browser. Uses the token to proceed with API requests.
Honestly I have no idea if this approach is legit...
The code of the action buttons should redirect to:
public async Task<IEnumerable<ExternalLoginDto>> GetExternalLogins(string returnUrl, bool generateState = false)
{
IEnumerable<AuthenticationScheme> loginProviders = await SignInManager.GetExternalAuthenticationSchemesAsync();
var logins = new List<ExternalLoginDto>();
string state;
if (generateState)
{
const int strengthInBits = 256;
state = RandomOAuthStateGenerator.Generate(strengthInBits);
}
else
{
state = null;
}
foreach (AuthenticationScheme authenticationScheme in loginProviders)
{
var routeValues = new
{
provider = authenticationScheme.Name,
response_type = "token",
client_id = Configuration["Jwt:Issuer"],
redirect_uri = $"{Request.Scheme}//{Request.Host}{returnUrl}",
state = state
};
var login = new ExternalLoginDto
{
Name = authenticationScheme.DisplayName,
Url = Url.RouteUrl("ExternalLogin", routeValues),
State = state
};
logins.Add(login);
}
return logins;
}
The code for the callback action:
[Authorize(AuthenticationSchemes = "Identity.External")]
[Route("ExternalLogin", Name = "ExternalLogin")]
public async Task<IActionResult> GetExternalLogin(string provider, string state = null, string client_id = null, string error = null)
{
if (error != null)
{
ThrowBadRequest(error);
}
if (!User.Identity.IsAuthenticated)
{
return new ChallengeResult(provider);
}
string providerKey = User.FindFirstValue(ClaimTypes.NameIdentifier);
var externalLoginInfo = new ExternalLoginInfo(User, User.Identity.AuthenticationType, providerKey, User.Identity.AuthenticationType);
if (externalLoginInfo.LoginProvider != provider)
{
await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);
return new ChallengeResult(provider);
}
var userLoginInfo = new UserLoginInfo(externalLoginInfo.LoginProvider, externalLoginInfo.ProviderKey, externalLoginInfo.ProviderDisplayName);
User user = await UserManager.FindByLoginAsync(externalLoginInfo.LoginProvider, externalLoginInfo.ProviderKey);
if (client_id != Configuration["Jwt:Issuer"])
{
return Redirect($"/#error=invalid_client_id_{client_id}");
}
if (user != null)
{
return await LoginWithLocalUser(user, state);
}
else
{
string email = null;
string firstName = null;
string lastName = null;
IEnumerable<Claim> claims = externalLoginInfo.Principal.Claims;
if (externalLoginInfo.LoginProvider == "Google")
{
email = claims.FirstOrDefault(c => c.Type == ClaimTypes.Email)?.Value;
firstName = claims.FirstOrDefault(c => c.Type == ClaimTypes.GivenName)?.Value;
lastName = claims.FirstOrDefault(c => c.Type == ClaimTypes.Surname)?.Value;
}
else if (externalLoginInfo.LoginProvider == "Facebook")
{
email = claims.FirstOrDefault(c => c.Type == ClaimTypes.Email)?.Value;
string[] nameParts = claims.First(c => c.Type == ClaimTypes.Name)?.Value.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
firstName = nameParts?.First();
lastName = nameParts?.Last();
}
//some fallback just in case
firstName ??= externalLoginInfo.Principal.Identity.Name;
lastName ??= externalLoginInfo.Principal.Identity.Name;
user = new User
{
UserName = email,
Email = email,
FirstName = firstName,
LastName = lastName,
EmailConfirmed = true //if the user logs in with Facebook consider the e-mail confirmed
};
IdentityResult userCreationResult = await UserManager.CreateAsync(user);
if (userCreationResult.Succeeded)
{
userCreationResult = await UserManager.AddLoginAsync(user, userLoginInfo);
if (userCreationResult.Succeeded)
{
return await LoginWithLocalUser(user, state);
}
}
string identityErrrors = String.Join(" ", userCreationResult.Errors.Select(ie => ie.Description));
Logger.LogWarning($"Error registering user with external login. Email:{email}, Errors:" + Environment.NewLine + identityErrrors);
return Redirect($"/#error={identityErrrors}");
}
}
private async Task<RedirectResult> LoginWithLocalUser(User user, string state)
{
await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);
DateTime expirationDate = DateTime.UtcNow.AddDays(365);
string token = user.GenerateJwtToken(Configuration["Jwt:Key"], Configuration["Jwt:Issuer"], expirationDate);
return Redirect($"/#access_token={token}&token_type=bearer&expires_in={(int)(expirationDate - DateTime.UtcNow).TotalSeconds}&state={state}");
}

Post message from Website to Facebook wall

I have a website made with ASP.NET webform .NET 4.5 C#. This site contains a forum(homemade by me), parts of this forum needs to be posted to the specific facebook wall(made for this webpage). What I need :
Post just created thread(message) from specific part of the forum to the corsponding facebook wall.
Optional : Sync the forum thread on webpage with message/comments on the specific facebook page
I have looked at these guides :
http://www.codeproject.com/Articles/569920/Publish-a-post-on-Facebook-wall-using-Graph-API
http://www.c-sharpcorner.com/UploadFile/raj1979/post-on-facebook-users-wall-using-Asp-Net-C-Sharp/
But im not sure that this is really the solution for me? I have tried to follow the guide but it does not look the same.
Edit :
dynamic result;
//https://developers.facebook.com/tools/explorer/
//https://developers.facebook.com/tools/access_token/
FacebookClient client = new FacebookClient(ConfigurationManager.AppSettings["FacebookAppToken"]);
//result = client.Get("debug_token", new
//{
// input_token = ConfigurationManager.AppSettings["FacebookAppToken"],
// access_token = ConfigurationManager.AppSettings["FacebookAppToken"]
//});
//result = client.Get("oauth/access_token", new
// {
// client_id = ConfigurationManager.AppSettings["FacebookAppId"],
// client_secret = ConfigurationManager.AppSettings["FacebookAppSecret"],
// grant_type = "client_credentials",
// //redirect_uri = "http://www.MyDomain.net/",
// //code = ""
// });
result = client.Get("oauth/access_token", new
{
client_id = ConfigurationManager.AppSettings["FacebookAppId"],
client_secret = ConfigurationManager.AppSettings["FacebookAppSecret"],
grant_type = "client_credentials"
});
client.AccessToken = result.access_token;
result = client.Post("[IdOfFacebookPage]/feed", new { message = "Test Message from app" });
//result.id;
result = client.Get("[IdOfFacebookPage]");
return false;
Approach to post to a facebook wall:
You need to register in facebook developer tools.
Create a app (fill a form).
Download FGT 5.0.480 (Facebook graph toolkit)
Reference FGT dlls in your web application.
FGT has methods to post to facebook wall but needs appId.
Use the app id of your app created in step 2.
To post to an user's wall through facebook, it is only possible through an app.
Try this asp .net app, which will allow you to post in your wall:
https://apps.facebook.com/aspdotnetsample/?fb_source=search&ref=br_tf
This will allow you to envision what you need.
Your app gets an appId with which you need to generate auth token.
Limitation: The user's wall where you want to post should have added the app created at step 2, this is compulsory and there is no work around.
When the user accesses the app for the first time, it automatically asks for permission to post to wall--> the user needs to accept it.
Hope this gives you an idea on how to go about doing this.
You can then post into the user's wall.
For Banshee's below request using Facebook SDK for .NET:
userId - facebook user id, wall to post the message
This user should have added the app created by you in step 1 else it will say unauthorized access.
dynamic messagePost = new ExpandoObject();
messagePost.picture = "http://www.stackoverflow.com/test.png";
messagePost.link = "http://www.stackoverflow.com";
messagePost.name = "This is a test name";
messagePost.caption = "CAPTION 1";
messagePost.description = "Test desc";
messagePost.message = "message"
var fb = new FacebookClient();
dynamic result = fb.Get("oauth/access_token", new {
client_id = "app_id",
client_secret = "app_secret",
grant_type = "client_credentials"
});
fb.AccessToken = result.access_token;
try
{
var postId = fb.Post(userId + "/feed", messagePost);
}
catch (FacebookOAuthException ex)
{
//handle oauth exception
}
catch (FacebookApiException ex)
{
//handle facebook exception
}
You will need an extended token to publish to a wall.. Steps to get extended token is explained well by Banshee..
Edit: How to get extended token by Banshee:
Please follow this post
By creating a extended page token and use it to make the post everything works just fine. See this : How to get Page Access Token by code?
Im surprised that this simple task was so hard to get running and that there was vary little help to get.

401 when attempting to Tweet with Linq to Twitter

So I've looked at all the of the suggestions from the Linq to Twitter documentation regarding 401 statuses with Oauth and I honestly don't know what I'm doing wrong.
var auth = new PinAuthorizer
{
Credentials = new InMemoryCredentials
{
ConsumerKey = ConfigurationManager.AppSettings["twitterConsumerKey"],
ConsumerSecret = ConfigurationManager.AppSettings["twitterConsumerSecret"],
//OAuthToken = ConfigurationManager.AppSettings["twitterOAuthToken"], //don't include this
//AccessToken = ConfigurationManager.AppSettings["twitterAccessToken"] //or this for new users.
},
//
UseCompression = true,
GoToTwitterAuthorization = pageLink => Process.Start(pageLink),
GetPin = () =>
{
Console.WriteLine("/nAfter twitter authorizes your application you will be returned here or something/n");
Console.Write("Enter Pin here:");
return Console.ReadLine();
}
};
auth.Authorize();
using (var twitterCtx = new TwitterContext(auth, "https://api.twitter.com/1/",
"https://search.twitter.com/"))
{
try
{
twitterCtx.Log = Console.Out;
Console.WriteLine("Please provide tweet text");
string tweet = Console.ReadLine();
twitterCtx.UpdateStatus(tweet);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
I've ran this using the Pin Authentication method as well as the single user method (providing the oauth keys with config file). I'm able to query tweets but I can't update my status or send direct messages (I receive a 403 forbidden when I try to DM). I've provided a callback URL (albeit fake) so I can't think of why this isn't working. Any help would be appreciated.
PS this runs in Main, not sure if that matters
All you need is this overload of the TwitterContext ctor and it will use the proper base URLs:
new TwitterContext(auth)
The example you're using is for v1.0 URLs and LINQ to Twitter is on Twitter API v1.1 now. It will default to the proper base URLs.
If you're querying okay, but getting errors on update and DM, double check to make sure you aren't trying to tweet the same text. That's why I append a DateTime.Now to the end of test tweets - to guarantee uniqueness.

Categories

Resources