I am able to login and tweet text message but not able to share an image on twitter.
When I upload the image it gives the response, but when I did not post image on twitter, I got the following response.
This is my code :-
private const string UploadMediaURL = "https://upload.twitter.com/1.1/media/upload.json";
public static IEnumerator UploadMedia(string consumerKey, string consumerSecret, AccessTokenResponse response)
{
Dictionary<string, string> parameters = new Dictionary<string,string>();
Texture2D tex= Resources.Load("imag") as Texture2D;
byte[] dataToSave = tex.EncodeToPNG ();
string encoded64ImageData = System.Convert.ToBase64String( dataToSave );
parameters.Add("media_data",encoded64ImageData);
WWWForm form = new WWWForm(); // Add data to the form to post.
form.AddField("media_data", encoded64ImageData );
Dictionary<string, string> headers = new Dictionary<string, string>();
string auth = GetHeaderWithAccessToken("POST", UploadMediaURL, consumerKey, consumerSecret, response, parameters);
Debug.Log ("Auth " + auth);
headers.Add( "Authorization", auth);
headers.Add( "Content-Transfer-Encoding","base64");
WWW web = new WWW(UploadMediaURL,form.data, headers);
yield return web;
Debug.Log ("Response " + web.text);
}
Response :-
{
"media_id":700577726298599424,
"media_id_string":"700577726298599424",
"size":9734,
"expires_after_secs":86400,
"image":
{
"image_type":"image\/png",
"w":435,
"h":159
}
}
This is my Posting Source Code With Media_Id. When I use it without media_id it posts successfully. But when I give a media_id parameter with it, it gives me an error
failed. 401 Unauthorized{"errors":[{"code":32,"message":"Could not authenticate you."}]}
Source Code:-
private const string PostTweetURL = "https://api.twitter.com/1.1/statuses/update.json";
public static IEnumerator PostTweet(string text, string consumerKey, string consumerSecret, AccessTokenResponse response, PostTweetCallback callback)
{
if (string.IsNullOrEmpty(text) || text.Length > 140)
{
Debug.Log(string.Format("PostTweet - text[{0}] is empty or too long.", text));
callback(false);
}
else
{
Dictionary<string, string> parameters = new Dictionary<string, string>();
parameters.Add("status", text);
WWWForm form = new WWWForm();
form.AddField("status", text);
form.AddField ("media_id", "732498072731713536");
// HTTP header
var headers = new Dictionary<string,string>();
headers["Authorization"] = GetHeaderWithAccessToken("POST", PostTweetURL, consumerKey, consumerSecret, response, parameters);
WWW web = new WWW(PostTweetURL, form.data, headers);
yield return web;
if (!string.IsNullOrEmpty(web.error))
{
Debug.Log(string.Format("PostTweet - failed. {0}\n{1}", web.error, web.text));
callback(false);
}
else
{
string error = Regex.Match(web.text, #"<error>([^&]+)</error>").Groups[1].Value;
if (!string.IsNullOrEmpty(error))
{
Debug.Log(string.Format("PostTweet - failed. {0}", error));
callback(false);
}
else
{
callback(true);
}
}
}
}
It makes perfect sense that this does not appear on twitter. The code you are currently provided is only meant to upload a image to the twitter service, which then can be attached in twitter status updates.
For example, a media_id value can be used to create a Tweet with an attached photo using the statuses/update endpoint. source
So after uploading your image, and receiving the media_id which can be used in the update
Updates the authenticating user’s current status, also known as Tweeting.
Edit
This is my Posting Source Code With Media_Id. When I use it without media_id it posts successfully. But when I give a media_id parameter with it, it gives me an error
failed. 401 Unauthorized{"errors":[{"code":32,"message":"Could not authenticate you."}]}
You are receiving this error because you are not being verified. As the error itself states as well. As mentioned in the update docs there are some things you have to keep in mind when uploading media. As mentioned here, POST and query parameters are not used when calculation an OAuth signature, unlike a general tweet.
Because the method uses multipart POST, OAuth is handled a little differently. POST or query string parameters are not used when calculating an OAuth signature basestring or signature. Only the oauth_* parameters are used.
Why no tweet has some pretty good answers in regards to this authentication.
Related
I'm working in an Unity app that needs to connect to a Microsoft Dynamics 365 which uses OAuth2.0. I was trying using UnityWebRequest to retrieve an access token by calling:
https://login.microsoftonline.com/[TENANT_ID]/oauth2/v2.0/token
using something similar to this thread:
OAuth2 Authentication and Operations in Unity
And it works, I'm able to get and access_token, however, when I try to consume the service with the Bearer token, I always get "401 unauthorized".
I then tried to call instead:
https://login.microsoftonline.com/[TENANT_ID]/oauth2/v2.0/authorize
But when I do that, the response is the actual HTML code of the Microsoft login screen. As far I know, getting an auth code requires a user interaction right? but I've been able to get this done by using Microsoft.IdentityModel.Clients.ActiveDirectory package from NuGet in a console C# app without user interaction, so there must be a way right?
I would really appreciate your help on this! thank you!
UPDATE 1 - My code
Get access token
private IEnumerator GetAccessToken(Action<string> result)
{
Dictionary<string, string> content = new Dictionary<string, string>();
//Fill key and value
content.Add("scope", "https://graph.microsoft.com/.default");
content.Add("grant_type", "client_credentials");
content.Add("client_id", "xxxxx");
content.Add("client_secret", "xxxx");
UnityWebRequest www = UnityWebRequest.Post("https://login.microsoftonline.com/[TENANTID]/oauth2/v2.0/token", content);
//Send request
yield return www.Send();
if (!www.isError)
{
string resultContent = www.downloadHandler.text;
TokenClassName json = JsonUtility.FromJson<TokenClassName>(resultContent);
//Return result
result(json.access_token);
}
else
{
//Return null
result("");
}
}
Call API
private IEnumerator GetData(Action<string> result)
{
Dictionary<string, string> content = new Dictionary<string, string>();
//Fill key and value
content.Add("CustomerGroupId", "10");
UnityWebRequest www = UnityWebRequest.Post("https://[ENVIRONMENT].cloudax.dynamics.com/data/TestEntity", content);
string token = null;
yield return GetAccessToken((tokenResult) => { token = tokenResult; });
result(token);
www.SetRequestHeader("Authorization", "Bearer " + token);
www.Send();
if (!www.isError)
{
string resultContent = www.downloadHandler.text;
// Perform additional operations...
}
}
The resource is different for the token and the API call. In the token request, the resource is https://graph.microsoft.com, it's not your destination API. You should request the token for your destination API.
【Problem】
The app was implemented by reference to below URL, can no longer sign-in with SSO.
URL: https://blogs.msdn.microsoft.com/omarv/2012/11/15/developing-windows-8-store-apps-for-sharepoint-online-with-sso-single-sign-on/
【The code that was copied from above URL】
const string msoHrdUrl = “https://login.microsoftonline.com/GetUserRealm.srf“;
private async Task<Uri> GetAdfsAuthUrl()
{
// make a post request with the user’s login name to
// MSO HRD (Home Realm Discovery) service so it can find
// out the url of the federation service (corporate ADFS)
// responsible for authenticating the user
byte[] response = await HttpUtility.SendHttpRequest(
new Uri(msoHrdUrl),
HttpMethod.Post,
new MemoryStream(Encoding.UTF8.GetBytes(String.Format(“handler = 1 & login ={ 0 }”, this.username))),
// pass in the login name in the body of the form
“application/x-www-form-urlencoded“,
null);
StreamReader sr = newStreamReader(new MemoryStream(response));
Dictionary<String, IJsonValue> dict = new Dictionary<string, IJsonValue>();
HttpUtility.ParseJson(JsonObject.Parse(Encoding.UTF8.GetString(response, 0, response.Length)), dict);
// the corporate STS url is in the AuthURL element of the response body
Uri corpAdfsProxyUrl = dict.ContainsKey(“AuthURL“) ? new Uri(dict[“AuthURL“].GetString()) : null;
return corpAdfsProxyUrl;
}
【Current Situation】
Send POST Request to “https://login.microsoftonline.com/GetUserRealm.srf“, but I got response with error below.
Error: "AADSTS90100: Invalid request. The Accept request parameter value 'application/x-www-form-urlencoded' is invalid."
When I changed method POST to GET and set json to Accept, I can get some values that I want and AuthURL("https://ADFS.CONTOSO.COM/adfs/ls/?username=USER%40CONTOSO.COM&wa=wsignin1.0&wtrealm=urn%3afederation%3aMicrosoftOnline&wctx=" ), but following behavior is different than before.
Ex) I cannot find value of “wresult” from Response that accessed to "https://ADFS.CONTOSO.COM/adfs/ls/auth/integrated/?username=USER%40CONTOSO.COM&wa=wsignin1.0&wtrealm=urn%3afederation%3aMicrosoftOnline&wctx="
【My Question】
I am not sure when this problem was occurred.
Does somebody have some information about this problem like this authentication function has changed?
The last time it went well is January in this year.
I am developing a web API to handle realtime updates (Lead information) from Facebook to integrate with my CRM.
In the WEB API POST request, I am able to capture the leadID but the problem comes when I get leadinfo by invoking FB.Get(LeadID). To make a Graph API GET request(for lead information) I need to have a user access token and this is where i have been struggling for quite sometime. I have looked up several posts online but havent got any solution for my problem.
In my sample implementation, GetLoginUrl(parameters) returns a uri and when when I request the uri in a browser, I see that the access token gets generated in the redirected Uri. But how to do this programatically ? I have tried the following
string FBAccessUrl = "https://graph.facebook.com/oauth/authorize?client_id=XXXXXXXXXXXX&response_type=token&redirect_uri=https://www.facebook.com/connect/login_success.html";
var accessTokenRequest = System.Net.HttpWebRequest.Create(FBAccessUrl);
HttpWebResponse response = (HttpWebResponse)accessTokenRequest.GetResponse();
but then i get this ResponseUri = {https://www.facebook.com/unsupportedbrowser} which is not what I want.
Can someone help me with how the user access token can be generated using C# in the Web API (without the facebook login dialog)
[HttpPost]
[ActionName("Complex")]
public void PostComplex(RootObject root)
{
FacebookClient fb = new FacebookClient();
// Get leadID from the inital HTTP POST request
long leadgen_id = root.entry[0].changes[0].value.leadgen_id;
string leadID = leadgen_id.ToString();
// to get user access token
dynamic parameters = new ExpandoObject();
parameters.client_id = "XXXXXXXXXXXXXXX";
parameters.redirect_uri = "https://www.facebook.com/connect/login_success.html";
parameters.response_type = "token";
// generate the login url
Uri uri = fb.GetLoginUrl(parameters);
// reuest the uri in browser and uri2 is the redirected uri
Uri uri2 = "****************"
string accesstoken = "";
FacebookOAuthResult oauthResult;
if (fb.TryParseOAuthCallbackUrl(uri, out oauthResult))
{
if (oauthResult.IsSuccess)
{
accesstoken = oauthResult.AccessToken;
}
else
{
var errorDescription = oauthResult.ErrorDescription;
var errorReason = oauthResult.ErrorReason;
}
}
fb.AccessToken = accesstoken;
string me = fb.Get(leadID).ToString();
// Then fetch required lead information
}
I've got an existing C# project with the following POST method:
// POST: /Account/ExternalLogin
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult ExternalLogin(string provider, string returnUrl)
{
return new ExternalLoginResult(provider, Url.Action("ExternalLoginCallback", new { ReturnUrl = returnUrl }));
}
Which uses:
OAuthWebSecurity.Login(provider, ...);
I'm kinda new to OAuth, and haven't done anything with it in this C# project. I do however implemented Google-authorization on an Android App, and I want to use the following class/method for the HttpPost:
public class TaskPostAPI extends AsyncTask<String, Void, String>
{
GoogleApiClient googleAPI;
public TaskPostAPI(GoogleApiClient googleAPI){
this.googleAPI = googleAPI;
}
#Override
protected String doInBackground(String... urls){
String response = "";
for(String url : urls){
DefaultHttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(url);
try{
List<NameValuePair> nvPairs = new ArrayList<NameValuePair>(2); //(3);
//nvPairs.add(new BasicNameValuePair("personName", Plus.PeopleApi.getCurrentPerson(googleAPI).getDisplayName()));
//nvPairs.add(new BasicNameValuePair("personGooglePlusProfile", Plus.PeopleApi.getCurrentPerson(googleAPI).getUrl()));
//nvPairs.add(new BasicNameValuePair("personEmail", Plus.AccountApi.getAccountName(googleAPI)));
nvPairs.add(new BasicNameValuePair("provider", ???));
URL u = new URL(url);
nvPairs.add(new BasicNameValuePair("returnUrl", u.getProtocol() + "://" + u.getHost()));
post.setEntity(new UrlEncodedFormEntity(nvPairs));
HttpResponse execute = client.execute(post);
InputStream content = execute.getEntity().getContent();
BufferedReader buffer = new BufferedReader(new InputStreamReader(content));
String s = "";
while((s = buffer.readLine()) != null)
response += s;
}
catch(Exception ex){
ex.printStackTrace();
}
}
return response;
}
}
So my question: What should I put at the POST-method's ???. So what is the Provider? In my Android App I log in using Google, and got the GoogleApiClient and Person (com.google.android.gms.plus.model.people.Person).
At this website I see the following url: https://accounts.google.com/o/oauth2/auth. Is this the url I should use as provider? Or should I add parameters to this url? Or should I use a completely different string as provider?
PS: If someone can send me a link to a list of provider-urls (like Google's, Facebook's, Twitter's, etc.) and how to use them for the C# OAuthWebSecurity I would appreciate it.
Thanks in advance for the responses.
Ok it turns out it was very simple.. The provider is just "Google", nothing more, nothing less.. This provider name I found at the RegisterClient method in de C# project:
OAuthWebSecurity.RegisterClient(client, "Google", extraData);
Now the POST works, except for the message "The required anti-forgery cookie "__RequestVerificationToken" is not present.", but at least I can continue. And adding a Cookie to a HttpPost isn't that hard I believe when using a CookieManager.
So I got this free plugin from the Unity asset store called Let's Tweet in Unity and it works perfectly for posting text but I cannot figure out how to use https://upload.twitter.com/1/statuses/update_with_media.xml
instead of http://api.twitter.com/1/statuses/update.xml?status={0} which is what it is using now. It is written in C# which I don't really know and I am not experienced in the twitter api either. In general I'm new to coding. I'm learning JS.
This plugin has done what I assume is the hardest part which is talking to twitter with the consumer key, secret, etc. The part that I am guessing needs to be changed is below but I could also send you the whole file.
private static readonly string PostTweetURL = "http://api.twitter.com/1/statuses/update.xml?status={0}";
public static IEnumerator PostTweet(string text, string consumerKey, string consumerSecret, AccessTokenResponse response, PostTweetCallback callback)
{
if (string.IsNullOrEmpty(text) || text.Length > 140)
{
Debug.Log(string.Format("PostTweet - text[{0}] is empty or too long.", text));
callback(false);
}
else
{
string url = string.Format(PostTweetURL, UrlEncode(text));
Dictionary<string, string> parameters = new Dictionary<string, string>();
parameters.Add("status", text);
// Need to fill body since Unity doesn't like an empty request body.
byte[] dummmy = new byte[1];
dummmy[0] = 0;
// HTTP header
Hashtable headers = new Hashtable();
headers["Authorization"] = GetHeaderWithAccessToken("POST", url, consumerKey, consumerSecret, response, parameters);
WWW web = new WWW(url, dummmy, headers);
yield return web;
if (!string.IsNullOrEmpty(web.error))
{
Debug.Log(string.Format("PostTweet - failed. {0}", web.error));
callback(false);
}
else
{
string error = Regex.Match(web.text, #"<error>([^&]+)</error>").Groups[1].Value;
if (!string.IsNullOrEmpty(error))
{
Debug.Log(string.Format("PostTweet - failed. {0}", error));
callback(false);
}
else
{
callback(true);
}
}
}
}
Try this: UniShare, it supports post photo to twitter. Besides, it also supports sharing to lots of other social platforms like Facebook, linked in, etc. And support iOS, Android, Mac.