getting access tokens forbidden 403 and some times 400 Bad Request - c#

I am facing the following issue while issuing request to retrieve the access token. First, I registered the application in developer console and consequently downloaded the client secret file. The content of which is as below: (i have marked secrets as xxxxx).
{"installed":{"client_id":"xxxx","auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://accounts.google.com/o/oauth2/token","auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs","client_secret":"xxxx","redirect_uris":["urn:ietf:wg:oauth:2.0:oob","http://localhost"]}}
In the developer documentation (located at : https://developers.google.com/identity/protocols/OAuth2InstalledApp ) however, it is given a different address to connect and retrieve the access tokens.
POST /oauth2/v3/token HTTP/1.1
Host: www.googleapis.com
Content-Type: application/x-www-form-urlencoded
I am confused
1. which URI's to use to get access to tokens.
2. What redirect_uri should be used? Is it the local host or the uri as noted in the developer documentation.
When i use the client secret token uri, i receive a 400 bad request and when i use the uri as noted in the developer documentation, I receive forbidden 403.
POST /oauth2/v3/token HTTP/1.1
Host: www.googleapis.com
Content-Type: application/x-www-form-urlencoded
Can someone kindly clarify. It would be an immense help.
I am writing a console application and i do not want to use the C# api already provided. The sample code is located below.
Where am I doing wrong?
string tokenUri = #"https://accounts.google.com/o/oauth2/token";
HttpWebRequest request=(HttpWebRequest) WebRequest.Create(tokenUri);
NameValueCollection outgoingQueryString = HttpUtility.ParseQueryString(String.Empty);
outgoingQueryString.Add("code", this.clientCode);
outgoingQueryString.Add("client_id", this.clientID);
outgoingQueryString.Add("client_secret", this.clientSecret);
outgoingQueryString.Add("redirect_uri", "https://oauth2-login-demo.appspot.com/code");
outgoingQueryString.Add("grant_type","authorization_code");
string postdata = outgoingQueryString.ToString();
byte[] byteArray = Encoding.UTF8.GetBytes(postdata);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = byteArray.Length;
Stream reqStr = request.GetRequestStream();
reqStr.Write(byteArray, 0, byteArray.Length);
reqStr.Flush();
reqStr.Close();
HttpWebResponse response=request.GetResponse() as HttpWebResponse;
Console.WriteLine(response.StatusCode.ToString());
Found out that url-encoded is not to be used, instead json is expected. revised the code as below and still 400 persist.
string tokenUri = "https://accounts.google.com/o/oauth2/token";
TokenFileds f = new TokenFileds() { client_code = this.clientCode, client_id = this.clientID, client_secret = this.clientSecret, redirect_uri = "urn:ietf:wg:oauth:2.0:oob", grant_type = "authorization_code" };
//string retString=this.SerializeToJson<TokenFileds>(f);
string retString = this.NewjsonLib(f);
byte[] byteArray=Encoding.UTF8.GetBytes(retString);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(tokenUri);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded;charset=utf-8";
request.ContentLength = byteArray.Length;
Stream strm = request.GetRequestStream();
strm.Write(byteArray, 0, byteArray.Length);
strm.Flush();
strm.Close();
HttpWebResponse response =request.GetResponse() as HttpWebResponse;

you need to insure few things before as,
1. While creating the project you have to select other type project.
2. You must enable the drive API's.
3. Then make sure you are posting this url L"/o/oauth2/token" to this server L"accounts.google.com".
4. you are giving Content Type as L"Content-Type: application/x-www-form-urlencoded".
5.and your header should be like this,
wstring wstrHeader = L"code="+ m_wstrAuthCode +
L"&client_id=327293200239-4n4a8ej3jlm1fdufqu7httclg5a28m1a.apps.googleusercontent.com&client_secret=ieEGhWhPhotp0ZegdgRLkOxv&redirect_uri=urn:ietf:wg:oauth:2.0:oob&grant_type=authorization_code";
here you have to replace m_wstrAuthCode to your authentication code.
6.then you will get the Json from server as,
{
"access_token" : "ya29.7gGjEgvIVIMOO7bHegijk2KygAVjjxz7bCOxUvG7OKeKTc66Nom1e9zCqSyzR4V0bTYC",
"token_type" : "Bearer",
"expires_in" : 3600,
"refresh_token" : "1/Vc9A7nfib4ikeYs0-TBfrs-isvjRDt-JI2ftj0pNVcRIgOrJDtdun6zK6XiATCKT"
}
7.you need to parse it to get the access token.

Related

Get auth token using post request

I am trying to get request auth token by making a post web request to a url. The api expects username/password as credentials in the form-data payload.
When I click the sign-in option on the browser, the network logs show a GET request with HTML as response, followed by a POST request which returns form-data with username/password and request token in payload.
Trying to mock the flow using webrequest, I am doing a simple post request, as the following:
public string HttpPost(string url, string post, string refer = "")
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
// request.CookieContainer = cJar;
request.UserAgent = UserAgent;
request.KeepAlive = false;
request.Method = "POST";
request.Referer = refer;
byte[] postBytes = Encoding.ASCII.GetBytes(post);
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = postBytes.Length;
Stream requestStream = request.GetRequestStream();
requestStream.Write(postBytes, 0, postBytes.Length);
requestStream.Close();
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
StreamReader sr = new StreamReader(response.GetResponseStream());
return sr.ReadToEnd();
}
However, this request only returns the text/HTML markup of the page as the first part of the request of the browser does. How do I get it to run the subsequent POST to fetch the token from the endpoint?
EDIT 1:
Here is the first GET Request:
The token is a CSRF token, what you need to do is find the login form in the html response that you've received with your initial get request, and also to ensure you are storing the cookies set in this response.
You will then need to search within the html response for the hidden input parameter named 'token' next to the username and pw input fields and use the value of that element to compose your post request.
Doing this programmatically is possible with some regex or the htmlagilitypack to extract that token

REST API PATCH request

I'm trying to send requests and get responses from MailChimp API . . so far, GET, POST and DELETE are working good however, PATCH always results to Bad Request can you identify the error in this code?
string data = "{\"name\": \"TestListTWOTWOTWO\"}";
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(uri);
request.Headers[HttpRequestHeader.Authorization] = accessToken;
request.Method = "PATCH";
request.ContentType = "text/plain;charset=utf-8";
System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
byte[] bytes = encoding.GetBytes(data);
request.ContentLength = bytes.Length;
using (Stream requestStream = request.GetRequestStream())
{
// Send the data.
requestStream.Write(bytes, 0, bytes.Length);
}
var response = (HttpWebResponse)request.GetResponse();
var responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();
the error occus on the line with request.GetResponse();
it is an unhandled WebException saying The remote server returned an error: (400) Bad Request
after checking the error response, here's the what it says
"Your request doesn't appear to be valid JSON:
\nParse error on line 1:\nPATCH /3.0/lists/9bb\n^\n
Expected one of: 'STRING', 'NUMBER', 'NULL', 'TRUE', 'FALSE', '{', '['"
Many C# libraries seem to try to use the Expect: 100-Continue header, which MailChimp/Akamai has a problem with when combined with PATCH. You have two options.
Turn off Expect: 100-Continue in your HTTP library. In one C# library, you do that with a line of code like Client.DefaultRequestHeaders.ExpectContinue = False
Tunnel the PATCH request through HTTP POST using the X-Http-Method-Override header. Here's more details on that header.
Cause PATCH is a quite new RFC, so you would not expect that more then a few services support it at all. You'd better check that if the service supports it.
You send request using json format, but set content type to "text/plain" is that OK?

Passing login info when sending HttpRequest to SFDC Web Service

Trying to send JSON HttpRequest to SFDC Web Service, get following response:
[1]
0: {
message: "Session expired or invalid"
errorCode: "INVALID_SESSION_ID"
}
How correctly pass session id or another information from LoginResult with HttpRequest? Code sample follows:
// Generate JSON
MyClass object = new MyClass();
string post_data = JsonSerializer.SerializeToString(object); // this is what we are sending
// this is where we will send it
string uri = "https://url.salesforce.com/some_path/";
// create a request
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
request.KeepAlive = false;
request.Method = "POST";
byte[] postBytes = Encoding.ASCII.GetBytes(post_data);
request.ContentType = "application/json";
request.ContentLength = postBytes.Length;
// Setup proxy and SFDC login
LoginResult result = SfdcConnection.GetLoginResult();
// ------------ Need to add login info here -----------------
// now send it
Stream requestStream = request.GetRequestStream();
requestStream.Write(postBytes, 0, postBytes.Length);
requestStream.Close();
// grab te response and print it out to the console along with the status code
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
string jsonResponse = new StreamReader(response.GetResponseStream()).ReadToEnd();
You need to pass the sessionId in the Authorization header, using the oauth pattern, so it'd be
request.Headers.Add("Authorization", "Bearer " + result.sessionId);
The sessionId is usable for quite some time, so just call login once, not before each REST api call.
This covered in more detail in the REST API docs.
You need to attach the LoginResult (which most likely contains the session ID) to your request, otherwise, the web service just sees a request with no session ID (and no cookies either), and has no way of verifying that you are the client that logged in.
pseudocode
LoginResult result = SfdcConnection.GetLoginResult();
// attach sesionId to your request, see the web services documentation for this
request.Headers.Add("sessionId", result.sessionId);

Instagram oAuth login fails with 403 Forbidden error using C# desktop app

I am developing my Instagram desktop app and I can't authorize user because of 403 Forbidden error.
I am stuck in getting the response from the login POST-request. My POST-string looks like so:
csrfmiddlewaretoken=98d25eec9c3d1a6935e5a491ff2fa543&username=myname&password=mypassword
and this is how i am forming my request:
Uri url = new Uri
("https://instagram.com/accounts/login/?next=/oauth/authorize/?client_id=" +
instagramClient_id + "&redirect_uri=" + instagramRedirectUrl +
"&response_type=token");
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.CookieContainer = cc;
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.KeepAlive = true;
byte[] sentData = Encoding.UTF8.GetBytes(data);
request.ContentLength = sentData.Length;
using (Stream requestStream = request.GetRequestStream())
{
requestStream.Write(sentData, 0, sentData.Length);
}
WebResponse response = request.GetResponse();
The result is - 403 Forbidden. Can't find out what am i doing wrong.
I can't help mentioning the fact that I have tested some other ways to complete the authorization and noticed that Google Chrome recieves much more cookies then C# request when working with Instagram. So far my desktop app doesn't receive a "sessionid", "__qca", "__utma", "__utmb", "__utmc", "__utmz", "ccode" and "user_segment" cookies. But it recieves "csrftoken" and "mid" cookies. Maybe that's why i'am always having a 403 error?
Add Referer header with the value of the request URL.

ASP.NET HTTP Authorization Header

I would like to know why my asp.net application will not add the header to my post when it is named 'Authorization' but will work fine when I change one character, say "Authorizations". In documentation for other sites they always use the name "Authorization" so I would like to as well and at this point I just want to under stand why.
I have read a few topics about this but have not found any logical reason why.
Here is my code below:
string fileName = "c:\\xyz.xml";
string uri = "http://myserver/Default.aspx";
req = WebRequest.Create(uri);
req.Method = "POST";
req.ContentType = "text/xml";
byte[] authBytes = Encoding.UTF8.GetBytes("DDSServices:jCole2011".ToCharArray());
req.Headers.Add("Authorization", "BASIC " + Convert.ToBase64String(authBytes) );
req.Headers.Add("test", "test");
UTF8Encoding encoder = new UTF8Encoding();
byte[] data = encoder.GetBytes(this.GetTextFromXMLFile(fileName));
req.ContentLength = data.Length;
Stream reqStream = req.GetRequestStream();
reqStream.Write(data, 0, data.Length);
reqStream.Close();
req.Headers.Add("Authorization", "BASIC" + Convert.ToBase64String(authBytes));
System.Net.WebResponse response = req.GetResponse();
System.IO.StreamReader reader = new StreamReader(response.GetResponseStream());
string str = reader.ReadToEnd();
The other annoying this is when i add the watched variable through fiddler it works fine.
I was ran into a question how to add Authentication/Credentials to the headers. I found the solution in the following way.
string _auth = string.Format("{0}:{1}", "myUser","myPwd");
string _enc = Convert.ToBase64String(Encoding.ASCII.GetBytes(_auth));
string _cred = string.Format("{0} {1}", "Basic", _enc);
req.Headers[HttpRequestHeader.Authorization] = _cred;
Which gave me those headers I want (pasted Wireshark descriptions),
Authorization: Basic bXlVc2VyOm15UHdk\r\n
Credentials: myUser:myPwd
For HTTP Basic Authorization, you should be using the Credentials property.
req.Credentials = new NetworkCredential("DDSServices", "jCole2011");
This should do what you want. Rather than setting the Authorization header.
NetworkCredential is a good solution but the site you are calling has to handle an unauthorized with a 401 AND a WWW-Authenticate header in the response.
Client:
request.Credentials = new CredentialCache {{aUri, "Basic", new NetworkCredential(aUserName, aPassword)}};
Server:
Response.ClearContent();
Response.StatusCode = 401;
Response.AddHeader("WWW-Authenticate", "Basic");
Response.End();
This will result in 2 hits to the server. The initial call will go to the server without credentials. When the server responds with a 401 AND the WWW-Authenticate header (with the type of authentication required), the request will be resent with the credentials in the request.

Categories