Using a token to search on Twitter with OAuth2 - c#

Before Twitter switched to OAuth2, I was using the following query:
string atomTweetSearchURL = string.Format("http://search.twitter.com/search.atom?q={0}", searchText);
This no longer works, so now I'm trying to switch to OAuth2. I manage to successfully retrieve a token, but once I've got this, I seem to be unable to actually perform the search. Here's the latest incarnation of what I've tried:
var searchUrl = string.Format("https://api.twitter.com/1.1/search/tweets.json?q={0}&access_token={1}&token_type={2}", srchStr, twitAuthResponse.access_token, twitAuthResponse.token_type);
WebRequest srchRequest = WebRequest.Create(searchUrl);
using (var response2 = await srchRequest.GetResponseAsync())
{
Stream stream = response2.GetResponseStream();
using (StreamReader sr = new StreamReader(stream))
{
string jsonResponse = await sr.ReadToEndAsync();
}
}
This gives me a 400 - bad request.
I've also tried building the request like this:
System.Net.Http.HttpClient srchRequest = new System.Net.Http.HttpClient();
string authHdr = string.Format(srchHeaderFormat, twitAuthResponse.token_type, twitAuthResponse.access_token);
srchRequest.DefaultRequestHeaders.Add("Authorization", authHdr);
There's a massive quantity of articles out there detailing how to do this, but none of them seem to work correctly with WinRT. Can anyone point me in the right direction?
EDIT
Here's my code to get the token:
var oAuthConsumerKey = key;
var oAuthConsumerSecret = secret;
var oAuthUri = new Uri("https://api.twitter.com/oauth2/token");
var authHeaderFormat = "Basic {0}";
var authHeader = string.Format(authHeaderFormat,
Convert.ToBase64String(Encoding.UTF8.GetBytes(Uri.EscapeDataString(oAuthConsumerKey)
+ ":" +
Uri.EscapeDataString((oAuthConsumerSecret)))
));
var req = new HttpClient();
req.DefaultRequestHeaders.Add("Authorization", authHeader);
HttpRequestMessage msg = new HttpRequestMessage(new HttpMethod("POST"), oAuthUri);
msg.Content = new HttpStringContent("grant_type=client_credentials");
msg.Content.Headers.ContentType = new Windows.Web.Http.Headers.HttpMediaTypeHeaderValue("application/x-www-form-urlencoded");
HttpResponseMessage response = await req.SendRequestAsync(msg);
TwitAuthenticateResponse twitAuthResponse;
using (response)
{
string objectText = await response.Content.ReadAsStringAsync();
twitAuthResponse = JSonSerialiserHelper.Deserialize<TwitAuthenticateResponse>(objectText);
}

With the 1.1 API you don't pass the access token as part of the url, you need to include it as the Authorization header as "Bearer access_token" so you were almost there!
EDIT
To do this in the Windows.Web.Http namespace the following works:
private static async Task SearchTweets(AuthenticationResponse twitAuthResponse)
{
string srchStr = "tweet";
var client = new HttpClient();
var searchUrl = string.Format("https://api.twitter.com/1.1/search/tweets.json?q={0}", srchStr);
var uri = new Uri(searchUrl);
client.DefaultRequestHeaders.Authorization = new HttpCredentialsHeaderValue("Bearer", twitAuthResponse.AccessToken);
var response2 = await client.GetAsync(uri);
string content = await response2.Content.ReadAsStringAsync();
}
Or with System.Net.Http use the following:
This code will run the search for srchStr using the access token you already acquired as you showed in the first example:
var client = new HttpClient();
var searchUrl = string.Format("https://api.twitter.com/1.1/search/tweets.json?q={0}", srchStr);
var uri = new Uri(searchUrl);
client.DefaultRequestHeaders.Add("Authorization", string.Format("Bearer {0}", twitAuthResponse.access_token));
HttpResponseMessage response = await client.GetAsync(uri);
Task<string> content = response.Content.ReadAsStringAsync();
EDIT
This is a strange one, I tested your code and you're right it does throw an exception when attempting to add the Auth header, however the code I had used for grabbing the Access Token is almost identical but uses the System.Net.Http methods rather than the Windows.Web.Http ones that you use and it works, so I'll provide my code here, maybe this is a bug in the framework, or someone else can provide some more insight! This also uses the JSON.NET library which can be found on NuGet.
private static async Task SearchTweets(AuthenticationResponse twitAuthResponse)
{
string srchStr = "tweet";
var client = new HttpClient();
var searchUrl = string.Format("https://api.twitter.com/1.1/search/tweets.json?q={0}", srchStr);
var uri = new Uri(searchUrl);
client.DefaultRequestHeaders.Add("Authorization", string.Format("Bearer {0}", twitAuthResponse.AccessToken));
HttpResponseMessage response2 = await client.GetAsync(uri);
string content = await response2.Content.ReadAsStringAsync();
}
private async void GetAuthenticationToken()
{
var client = new HttpClient();
var uri = new Uri("https://api.twitter.com/oauth2/token");
var encodedConsumerKey = WebUtility.UrlEncode(TwitterConsumerKey);
var encodedConsumerSecret = WebUtility.UrlEncode(TwitterConsumerSecret);
var combinedKeys = String.Format("{0}:{1}", encodedConsumerKey, encodedConsumerSecret);
var utfBytes = System.Text.Encoding.UTF8.GetBytes(combinedKeys);
var encodedString = Convert.ToBase64String(utfBytes);
client.DefaultRequestHeaders.Add("Authorization", string.Format("Basic {0}", encodedString));
var data = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("grant_type", "client_credentials")
};
var postData = new FormUrlEncodedContent(data);
var response = await client.PostAsync(uri, postData);
AuthenticationResponse authenticationResponse;
using (response)
{
if (response.StatusCode != System.Net.HttpStatusCode.OK)
throw new Exception("Did not work!");
var content = await response.Content.ReadAsStringAsync();
authenticationResponse = JsonConvert.DeserializeObject<AuthenticationResponse>(content);
if (authenticationResponse.TokenType != "bearer")
throw new Exception("wrong result type");
}
await SearchTweets(authenticationResponse);
}
}
class AuthenticationResponse
{
[JsonProperty("token_type")]
public string TokenType { get; set; }
[JsonProperty("access_token")]
public string AccessToken { get; set; }
}

Related

Executing POST request for Microsoft Graph API to add members to an AD group

I am trying to add members to an AD groups invoking Microsoft Graph API through an Azure Function
It is very easy and straightforward to execute GET requests through Graph API's, but I can't find any examples how I could execute post requests for the Graph API
I do have an example of a post request for the Graph API which is
POST https://graph.microsoft.com/v1.0/groups/{id}/members/$ref
Content-type: application/json
Content-length: 30
{
"#odata.id": "https://graph.microsoft.com/v1.0/directoryObjects/{id}"
}
Here is the code I successfully use to retrieve the Graph response
public static async Task<HttpResponseMessage> GetDirectoryUsers(string graphToken, TraceWriter log, string displayName)
{
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", graphToken);
string requestUrl = "https://graph.microsoft.com/v1.0/groups?$top=2&$filter=displayName eq '" + displayName + "'&$expand=Members";
var request = new HttpRequestMessage(new HttpMethod("GET"), requestUrl);
var response = await client.SendAsync(request);
return response;
}
However, I am completely lost how I could execute the request through a C# code within the Azure function to ADD the retrieved users to another AD. How can construct the request URL? How should I handle the odata id within that request URL?
If anyone could help me in any way, I would greatly appreciate it
A reuse method for add sub-group/member to group(O365 doesn't support add sub-group to group now)
/// <param name="graphClient"></param>
/// <param name="groupId"></param>
/// <param name="memberId">memberId/sub-group id</param>
/// <returns></returns>
public static async Task AddGroupMember1(GraphServiceClient
graphClient, string groupId, string memberId)
{
User memberToAdd = new User { Id = memberId };
//Group memberToAdd= new Group { Id = memberId };
await graphClient.Groups[groupId].Members.References.Request().AddAsync(memberToAdd);
}
Here is the answer that worked for me
public static async Task<string> AddGroupMember(string accessToken, string groupId, string memberId)
{
var status = string.Empty;
try
{
string endpoint = "https://graph.microsoft.com/v1.0/groups/" + groupId + "/members/$ref";
string queryParameter = "";
// pass body data
var keyOdataId = "#odata.id";
var valueODataId = "https://graph.microsoft.com/v1.0/directoryObjects/" + memberId;
var values = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>(keyOdataId, valueODataId)
};
var jsonData = $#"{{ ""{keyOdataId}"": ""{valueODataId}"" }}";
var body = new StringContent(jsonData, Encoding.UTF8, "application/json");
using (var client = new HttpClient())
{
using (var request = new HttpRequestMessage(HttpMethod.Post, endpoint + queryParameter))
{
request.Content = body;
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
using (var response = await client.SendAsync(request))
{
if (response.StatusCode == HttpStatusCode.NoContent)
status = "Member added to Group";
else
status = $"Unable to add Member to Group: {response.StatusCode}";
}
}
}
}
catch (Exception ex)
{
status = $"Error adding Member to Group: {ex.Message}";
}
return status;
}
I'm using graph api for sending email. The code in below
public async Task<dynamic> SendMail(string accessToken, MailWrapper mail)
{
try
{
GraphServiceClient graphClient = SDKHelper.GetMicrosoftAuthenticatedClient(accessToken);
Message message = await BuildEmailMessage(graphClient, mail);
await graphClient.Me.SendMail(message, true).Request().PostAsync(CancellationToken.None);
var response = await graphClient.Me.MailFolders.SentItems.Messages.Request()
.OrderBy(sendDateTimeDesc)
.Top(1)
.GetAsync();
return await Task.FromResult(response);
}
catch (ServiceException ex)
{
throw ex;
}
}
Assembly Microsoft.Graph, Version=1.9.0.0
That's what worked for me
public void AddUserToGroup(string groupId)
{
var requestUri = $"{_graphApiUrl}/v1.0/groups/{groupId}/members/$ref";
var id = "user_id";
var OdataId = "#odata.id";
var ODataValue = $"https://graph.microsoft.com/v1.0/users/{id}";
var content = $#"{{ ""{OdataId}"": ""{ODataValue}"" }}";
using (var httpClient = new HttpClient())
using (var httpRequest = CreateHttpRequest(HttpMethod.Post, requestUri, content))
{
var response = httpClient.SendAsync(httpRequest).GetAwaiter().GetResult();
if (!response.IsSuccessStatusCode)
{
var reason = $"Status code: {(int)response.StatusCode}, Reason: {response.StatusCode}";
throw new Exception(reason);
}
}
}
And important thing was when creating a request to use:
request.Content = new StringContent(content, Encoding.UTF8, "application/json");
it didn't work with:
request.Content = new StringContent(content);
request.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json;odata=verbose");

Using HttpClient to GET

So, because HttpClient is "better," I need to convert WebClient to HttpClient, but it just doesn't work as expected. The following function uses WebClient and works like a charm.
private static void Authenticate()
{
Console.WriteLine("Authenticating . . .");
var clientId = ConfigurationManager.AppSettings["AuthNClientId"];
var uri = ConfigurationManager.AppSettings["AuthNUri"];
var userName = ConfigurationManager.AppSettings["AuthNUserName"];
var password = ConfigurationManager.AppSettings["AuthNPassword"];
var client = new WebClient();
string formData = $"client_id={clientId}&grant_type=password&username={userName}&password={password}";
client.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
var response = client.UploadString($"{uri}", formData);
dynamic authResult = JsonConvert.DeserializeObject(response);
_accessToken = authResult.access_token;
if (_accessToken == null)
{
throw new ApplicationException("Unable to authenticate. Check your configuration file <appSettings>.");
}
Console.WriteLine("Authenticated.");
}
This code, on the other hand, returns a BadRequest response code.
static async Task<string> GetAuthenticationToken()
{
string token = string.Empty;
var clientId = ConfigurationManager.AppSettings["AuthNClientId"];
var uri = ConfigurationManager.AppSettings["AuthNUri"];
var userName = ConfigurationManager.AppSettings["AuthNUserName"];
var password = ConfigurationManager.AppSettings["AuthNPassword"];
client.BaseAddress = new Uri("https://myurl.com/oauth2/token");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Add("ContentType", "application/x-www-form-urlencoded");
var path = $"client_id={clientId}&grant_type=password&username={userName}&password={password}";
HttpResponseMessage response = await client.GetAsync($"https://myurl.com/oauth2/token?{path}");
if (response.IsSuccessStatusCode)
{
Console.WriteLine("success");
token = await response.Content.ReadAsStringAsync();
}
else { Console.WriteLine($"failure: {response.StatusCode}"); }
return token;
}
You can see that I've tried it a couple of ways, including setting the client BaseAddress as well as just try to pass the url into the GetAsync method.
Anyone see what I'm doing wrong here?
UploadString is a POST method in the first example. In the second example a GET method is being done.
static async Task<string> GetAuthenticationTokenAsync() {
string token = string.Empty;
var clientId = ConfigurationManager.AppSettings["AuthNClientId"];
var uri = ConfigurationManager.AppSettings["AuthNUri"];
var userName = ConfigurationManager.AppSettings["AuthNUserName"];
var password = ConfigurationManager.AppSettings["AuthNPassword"];
var client = new HttpClient();
client.BaseAddress = new Uri(uri);
client.DefaultRequestHeaders.Accept.Clear();
var nameValueCollection = new Distionary<string, string>() {
{ "client_id", clientId },
{ "grant_type", "password" },
{ "username", userName },
{ "password", password },
};
var content = new FormUrlEncodedContent(nameValueCollection);
var response = await client.PostAsync("", content);
if (response.IsSuccessStatusCode) {
Console.WriteLine("success");
var json = await response.Content.ReadAsStringAsync();
dynamic authResult = JsonConvert.DeserializeObject(json);
token = authResult.access_token;
}
else { Console.WriteLine($"failure: {response.StatusCode}"); }
return token;
}

How to implement oauth2 of Twitter on UWP?

I want to develop a small twitter application on UWP .
GET oauth/authenticate
GET oauth/authorize
POST oauth/access_token
POST oauth/request_token
POST oauth2/invalidate_token
POST oauth2/token
It is more information. I'm confused. So I want to login to Twitter by ComsumerKey, ComsumerKeySecret, Callback Uri. and get access_token to access data from api.twitter.com.
I think that I've to use POST oauth2/token before(Is it wrong?).
<!-- begin snippet: C# hide: false console: true babel: false -->
<!-- language: lang-html -->
public async Task<string> GetAccessTokenBYAuthorizeTwitter()
{
//throw new NotImplementedException();
var client = new HttpClient();
string postData = "grant_type=client_credentials";
var request = await client.PostAsync(ResourceUrl,new StringContent(postData));
//request headers
client.DefaultRequestHeaders.Add("Authorization", string.Format("Basic {0}", Convert.ToBase64String(Encoding.UTF8.GetBytes(ComsumerKeyAndSecret))));
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
return await request.Content.ReadAsStringAsync();
}
<!-- end snippet -->
Example : I try to login by Vimeo and successful.
public async Task<string> AuthorizeWithVimeo()
{
var clientId = "b8e1bff5d5d1f2c90f61017b135960adb42f5fe2";
var SpotifyUrl = "https://api.vimeo.com/oauth/authorize?client_id=" + Uri.EscapeDataString(clientId) + "&response_type=code&redirect_uri=" + Uri.EscapeDataString("https://example/callback") + "&state=xyzbc";
var StartUri = new Uri(SpotifyUrl);
var EndUri = new Uri("https://example/callback");
WebAuthenticationResult WebAuthenticationResult = await WebAuthenticationBroker.AuthenticateAsync(WebAuthenticationOptions.None, StartUri, EndUri);
if (WebAuthenticationResult.ResponseStatus == WebAuthenticationStatus.Success)
{
var responseData = WebAuthenticationResult.ResponseData;
//await GetSpotifyUserNameAsync(WebAuthenticationResult.ResponseData.ToString());
return responseData;
}
else if (WebAuthenticationResult.ResponseStatus == WebAuthenticationStatus.ErrorHttp)
{
return $"HTTP Error returned by AuthenticateAsync() : {WebAuthenticationResult.ResponseErrorDetail.ToString()}";
}
else
{
return $"Error returned by AuthenticateAsync() : {WebAuthenticationResult.ResponseStatus.ToString()}";
}
}
This should work
var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
"Basic",
Convert.ToBase64String(
Encoding.ASCII.GetBytes(
string.Format("{0}:{1}", Uri.EscapeDataString(oauth_consumer_key),
Uri.EscapeDataString(oauth_consumer_secret)))));
client.DefaultRequestHeaders.TryAddWithoutValidation("Accept-Encoding", "gzip");
client.DefaultRequestHeaders.TryAddWithoutValidation("Host", "api.twitter.com");
var content = new StringContent(postBody);
content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");
HttpResponseMessage response =await client.PostAsync(oauth_url, content);
response.EnsureSuccessStatusCode();
using (var responseStream = response.Content.ReadAsStreamAsync())
using (var decompressedStream = new GZipStream(responseStream.Result, CompressionMode.Decompress))
using (var streamReader = new StreamReader(decompressedStream))
{
var rawJWt = streamReader.ReadToEnd();
var jwt = JsonConvert.DeserializeObject(rawJWt);
}
More info

Paypal Rest Api With RestSharp not working in xamarin android

I have got error with RestSharp component when i am call Paypal Rest API.
I have the following code using Xamarin for Android.
public async Task<PayPalGetTokenResponse> GetAccessToken()
{
var restRequest = new RestRequest("/oauth2/token", Method.POST);
// Add headers
restRequest.AddHeader("Accept", "application/json");
restRequest.AddHeader("Accept-Language", "en_US");
// Make Authorization header
restClient.Authenticator = new HttpBasicAuthenticator(Config.ApiClientId, Config.ApiSecret);
// add data to send
restRequest.AddParameter("grant_type", "client_credentials");
var response = restClient.Execute<PayPalGetTokenResponse>(restRequest);
response.Data.DisplayError = CheckResponseStatus(response, HttpStatusCode.OK);
return response.Data;
}
But got error :"Error: SecureChannelFailure (The authentication or decryption has failed.)"
I have Also use ModernHttpClient but got same error
public async Task<PayPalGetTokenResponse> GetAccessToken()
{
string clientId = Config.ApiClientId;
string secret = Config.ApiSecret;
string oAuthCredentials = Convert.ToBase64String(Encoding.Default.GetBytes(clientId + ":" + secret));
string uriString = Config.ApiUrl+"/oauth2/token";
PayPalGetTokenResponse result;
HttpClient client = new HttpClient(new NativeMessageHandler());
var h_request = new HttpRequestMessage(HttpMethod.Post, uriString);
h_request.Headers.Authorization = new AuthenticationHeaderValue("Basic", oAuthCredentials);
h_request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
h_request.Headers.AcceptLanguage.Add(new StringWithQualityHeaderValue("en_US"));
h_request.Content = new StringContent("grant_type=client_credentials", UTF8Encoding.UTF8);
try
{
HttpResponseMessage response = await client.SendAsync(h_request);
//if call failed ErrorResponse created...simple class with response properties
if (!response.IsSuccessStatusCode)
{
var error = await response.Content.ReadAsStringAsync();
var errResp = JsonConvert.DeserializeObject<string>(error);
//throw new PayPalException { error_name = errResp.name, details = errResp.details, message = errResp.message };
}
var success = await response.Content.ReadAsStringAsync();
result = JsonConvert.DeserializeObject<PayPalGetTokenResponse>(success);
}
catch (Exception)
{
throw new HttpRequestException("Request to PayPal Service failed.");
}
return result;
}
Have you tried to force to modern day SSL protocol?
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
This works for me:
if (ServicePointManager.SecurityProtocol != SecurityProtocolType.Tls12)
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
var client = new RestClient(payPalURL) {
Encoding = Encoding.UTF8
};
var authRequest = new RestRequest("oauth2/token", Method.POST) {
RequestFormat = DataFormat.Json
};
client.Authenticator = new HttpBasicAuthenticator(clientId, secret);
authRequest.AddParameter("grant_type","client_credentials");
var authResponse = client.Execute(authRequest);

Getting Tweets in MVC

I am trying to load tweets but my code isn't working when using my MVC app. However, the exact code works when using a console.
I am asuming it is something to do with "async", I have not had experience using this before and I am unable to find a solution. Break points after "GetAccessToken()" are not hit
In my Controler:
public ActionResult Tweets(int tweets, string username)
{
var twitter = new Twitter();
var userTweets = twitter.GetTweets("chrishall9521", 10).Result.ToList();
this.ViewBag.Tweets = userTweets;
return View();
}
In my "Twitter" class:
public async Task<IEnumerable<string>> GetTweets(string userName, int count)
{
var accessToken = await GetAccessToken();
var requestUserTimeline = new HttpRequestMessage(HttpMethod.Get, string.Format("https://api.twitter.com/1.1/statuses/user_timeline.json?count={0}&screen_name={1}&trim_user=1&exclude_replies=1", count, userName));
requestUserTimeline.Headers.Add("Authorization", "Bearer " + accessToken);
var httpClient = new HttpClient();
HttpResponseMessage responseUserTimeLine = await httpClient.SendAsync(requestUserTimeline);
var serializer = new JavaScriptSerializer();
dynamic json = serializer.Deserialize<object>(await responseUserTimeLine.Content.ReadAsStringAsync());
var enumerableTwitts = (json as IEnumerable<dynamic>);
if (enumerableTwitts == null)
{
return null;
}
return enumerableTwitts.Select(t => (string)(t["text"].ToString()));
}
public async Task<string> GetAccessToken()
{
var httpClient = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://api.twitter.com/oauth2/token ");
var customerInfo = Convert.ToBase64String(new UTF8Encoding().GetBytes(OAuthConsumerKey + ":" + OAuthConsumerSecret));
request.Headers.Add("Authorization", "Basic " + customerInfo);
request.Content = new StringContent("grant_type=client_credentials", Encoding.UTF8, "application/x-www-form-urlencoded");
var response = await httpClient.SendAsync(request).ConfigureAwait(false);
string json = await response.Content.ReadAsStringAsync();
var serializer = new JavaScriptSerializer();
dynamic item = serializer.Deserialize<object>(json);
return item["access_token"];
}
Don't use .Result like that - you're deadlocking. Use await in the Tweets method instead and make it async. The basic "golden rule" for using async is that when you use it, you use it all the way up the chain.
Here's a blog post with similar examples for further reading.

Categories

Resources