How to get access token for google oauth? - c#

I am using C# (ASP.NET). I want to use Google OAuth for accessing the user profile detail in my app. I successfully got the authorization code but having a problem in getting the access token.
I prefer the Google tutorials. In tutorial, I read that I have to send the request and get the response from google. For that, I use System.Net.HttpWebRequest/HttpWebResponse (am I going in the right way). I have used this code...
byte[] buffer = Encoding.ASCII.GetBytes("?code=" + code + "&client_id=xxx&client_secret=xxx&redirect_uri=xxxx&grant_type=authorization_code");
HttpWebRequest req = (HttpWebRequest)WebRequest.Create("http://accounts.google.com");
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
req.ContentLength = buffer.Length;
Stream strm = req.GetRequestStream();
strm.Write(buffer, 0, buffer.Length);
strm.Close();
HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
Response.Write(((HttpWebResponse)resp).StatusDescription);
But, I got the error:
The remote server returned an error: (405) Method Not Allowed.
Update: Here variable code is authorization code.

I think you are sending the POST request to the wrong endpoint, the correct one is https://accounts.google.com/o/oauth2/token

As I had similar problems in the process of implementing Google auth, I will post the code that works.. The last mentioned problem: error (400) Bad request could be caused by leading '?' in the above code..
string codeClient = "code="+ t +"&client_id=number.apps.googleusercontent.com&";
string secretUri = "client_secret=yoursecret&" + "redirect_uri=path&"
+ "grant_type=authorization_code";
postString = codeClient + secretUri;
string url = "https://accounts.google.com/o/oauth2/token";
HttpWebRequest request = (HttpWebRequest) WebRequest.Create(url.ToString());
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
UTF8Encoding utfenc = new UTF8Encoding();
byte[] bytes = utfenc.GetBytes(postString);
Stream os = null;
try
{
request.ContentLength = bytes.Length;
os = request.GetRequestStream();
os.Write(bytes, 0, bytes.Length);
}
catch
{ }
try
{
HttpWebResponse webResponse = (HttpWebResponse) request.GetResponse();
Stream responseStream = webResponse.GetResponseStream();
StreamReader responseStreamReader = new StreamReader(responseStream);
result = responseStreamReader.ReadToEnd();//parse token from result

My code is working, I have done mistakes in above two lines. It should be like this
byte[] buffer = Encoding.ASCII.GetBytes("code=" + code + "&client_id=xxx&client_secret=xxx&redirect_uri=xxxx&grant_type=authorization_code");
HttpWebRequest req = (HttpWebRequest)WebRequest.Create("https://accounts.google.com/o/oauth2/token");
Remaining code is correct.

The original request seems to be somewhat outdated. But I found that the Google's code examples contain lots of "Best Practices" housekeeping code that's hard to separate from the essential operations.
I recently published a document that represents all the REST operations as curl commands. It's hard to be conversant in every language, but curl seems universal. Most people know it- otherwise, it's pretty easy to grasp. In my curl examples, the -d flag indicates a POST operation. Otherwise, the parameters are appended to the URL.
http://www.tqis.com/eloquency/googlecalendar.htm

public string ReceiveTokenGmail(string code, string GoogleWebAppClientID, string GoogleWebAppClientSecret, string RedirectUrl)
{
string postString = "code=" + code + "&client_id=" + GoogleWebAppClientID + #"&client_secret=" + GoogleWebAppClientSecret + "&redirect_uri=" + RedirectUrl;
string url = "https://accounts.google.com/o/oauth2/token";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url.ToString());
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
UTF8Encoding utfenc = new UTF8Encoding();
byte[] bytes = utfenc.GetBytes(postString);
Stream os = null;
try
{
request.ContentLength = bytes.Length;
os = request.GetRequestStream();
os.Write(bytes, 0, bytes.Length);
}
catch
{ }
string result = "";
HttpWebResponse webResponse = (HttpWebResponse)request.GetResponse();
Stream responseStream = webResponse.GetResponseStream();
StreamReader responseStreamReader = new StreamReader(responseStream);
result = responseStreamReader.ReadToEnd();
return result;
}

It was surprisingly difficult to find the correct and simple way of getting access token by auth code. (Especially because it has taken some time for me and then even with the correct code I got “invalid_grant” error because my auth code expired while searching :) )
So here is the code:
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow(
new GoogleAuthorizationCodeFlow.Initializer
{
ClientSecrets = new ClientSecrets()
{
// Use ones from "Web SDK configuration" section if you created your app in Firebase.
ClientId = "…",
ClientSecret = "…"
},
Scopes = new[] { "email" },
}
);
TokenResponse token = await flow.ExchangeCodeForTokenAsync(string.Empty, "4/…", string.Empty, CancellationToken.None);
As you can see, userId can be just empty, as well as redirectUri.
Don’t forget to add the Google.Apis.Auth Nuget package reference.

Related

Is there any possibility to send post with body using OAuth 1.0?

i am trying to send a POST request with body to WordPress API. I am still getting 401 error.
I decided to use: https://gist.github.com/DeskSupport/2951522 to authorize via OAuth 1.0 and it works perfectly with GET method. Then i wanted to implement another method which sends simple body.
That's my code:
var oauth = new OAuth.Manager();
oauth["consumer_key"] = _consumerKey;
oauth["consumer_secret"] = _consumerSecret;
oauth["token"] = _accessToken;
oauth["token_secret"] = _tokenSecret;
var appUrl = _baseUrl + url;
var authzHeader = oauth.GenerateAuthzHeader(appUrl, "POST");
string body = GenerateBody(parameters);
byte[] encodedData = Encoding.ASCII.GetBytes(body);
var request = (HttpWebRequest)WebRequest.Create(appUrl);
request.Method = "POST";
request.PreAuthenticate = true;
request.AllowWriteStreamBuffering = true;
request.Headers.Add("Authorization", authzHeader);
request.ContentLength = encodedData.Length;
request.ContentType = "application/x-www-form-urlencoded";
Stream newStream = request.GetRequestStream();
newStream.Write(encodedData, 0, encodedData.Length);
using (var response = (HttpWebResponse)request.GetResponse())
{
if (response.StatusCode != HttpStatusCode.OK)
{
}
}
The result of method GenerateBody is user_login=login&user_pass=BXE&04K44DoR1*a
I also tried to change the '&' character to '%26' but it didn't work.
This request works via Postman and i don;t know what's wrong.
OK, I found a solution.
https://blog.dantup.com/2016/07/simplest-csharp-code-to-post-a-tweet-using-oauth/
This guy wrote the way to make this request. What is also important you have to change a oauth_nonce for unique token.

Google API response time very high

I am using google RESTApis to manage google calendar
One particular api call to check current "access token is valid or not" is taking extra time(2 minutes) only in azure environment and the same call is only taking few seconds in localhost and other non azure environments.
string url = "https://www.googleapis.com/oauth2/v2/tokeninfo?access_token=" + AccessToken;
var request = (HttpWebRequest)WebRequest.Create(url);
request.ContentType = "application/x-www-form-urlencoded";
request.Method = "POST";
byte[] bytes = Encoding.UTF8.GetBytes(string.Empty);
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls11;
using (var stream = request.GetRequestStream())
{
stream.Write(bytes, 0, bytes.Length); //Push it out there
}
var resp = request.GetResponse();
Any help would be appreciated. Thanks in advance.

using OpenTSDB HTTP api in .NET : 400 Bad Request

I'm trying to use .net to put datapoints in OpenTSDB, using the HTTP /api/put API.
I've tried with httpclient, webRequest and HttpWebRequest. The outcome is always 400 - bad request: chunked request not supported.
I've tried my payload with an api tester (DHC) and works well.
I've tried to send a very small payload (even plain wrong, like "x") but the reply is always the same.
Here's one of my code instances:
public async static Task PutAsync(DataPoint dataPoint)
{
try
{
HttpWebRequest http = (HttpWebRequest)WebRequest.Create("http://127.0.0.1:4242/api/put");
http.SendChunked = false;
http.Method = "POST";
http.ContentType = "application/json";
Encoding encoder = Encoding.UTF8;
byte[] data = encoder.GetBytes( dataPoint.ToJson() + Environment.NewLine);
http.Method = "POST";
http.ContentType = "application/json; charset=utf-8";
http.ContentLength = data.Length;
using (Stream stream = http.GetRequestStream())
{
stream.Write(data, 0, data.Length);
stream.Close();
}
WebResponse response = http.GetResponse();
var streamOutput = response.GetResponseStream();
StreamReader sr = new StreamReader(streamOutput);
string content = sr.ReadToEnd();
Console.WriteLine(content);
}
catch (WebException exc)
{
StreamReader reader = new StreamReader(exc.Response.GetResponseStream());
var content = reader.ReadToEnd();
}
return ;
}
where I explicitly set to false the SendChunked property.
note that other requests, like:
public static async Task<bool> Connect(Uri uri)
{
HttpWebRequest http = (HttpWebRequest)WebRequest.Create("http://127.0.0.1:4242/api/version");
http.SendChunked = false;
http.Method = "GET";
// http.Headers.Clear();
//http.Headers.Add("Content-Type", "application/json");
http.ContentType = "application/json";
WebResponse response = http.GetResponse();
var stream = response.GetResponseStream();
StreamReader sr = new StreamReader(stream);
string content = sr.ReadToEnd();
Console.WriteLine(content);
return true;
}
work flawlessly.
I am sure I am doing something really wrong.
I'd like to to reimplement HTTP in Sockets from scratch.
I've found a solution I'd like to share here.
I've used wireshark to sniff my packets, and I've found that this header is added:
Expect: 100-continue\r\n
(see 8.2.3 of https://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html)
This is the culprit. I've read the post http://haacked.com/archive/2004/05/15/http-web-request-expect-100-continue.aspx/ by Phil Haack, and found that HttpWebRequest puts that header by default, unless you tell it to stop. In this article I've found that using ServicePointManager I can do just this.
Putting the following code on top of my method, when declaring the http object, makes it work very well, and solves my issue:
var uri = new Uri("http://127.0.0.1:4242/api/put");
var spm = ServicePointManager.FindServicePoint(uri);
spm.Expect100Continue = false;
HttpWebRequest http = (HttpWebRequest)WebRequest.Create(uri);
http.SendChunked = false;

scrape site after login

I'm trying to scrape a website that requires a login. Getting an error that I haven't received before, copied the code from another forum successfully in the past:
Exception Details: System.Net.ProtocolViolationException: Cannot send a content-body with this verb-type.
with the code:
Stream newStream = http.GetRequestStream(); //open connection
Here's the entire code:
#{
var strUserId = "userName";
var strPassword = "password";
var url = "formSubmitLandingSite";
var url2 = "pageToScrape";
HttpWebRequest http = WebRequest.Create(url) as HttpWebRequest;
http.KeepAlive = true;
http.Method = "POST";
http.ContentType = "application/x-www-form-urlencoded";
string postData = "email=" + strUserId + "&password=" + strPassword;
byte[] dataBytes = UTF8Encoding.UTF8.GetBytes(postData);
http.ContentLength = dataBytes.Length;
using (Stream postStream = http.GetRequestStream())
{
postStream.Write(dataBytes, 0, dataBytes.Length);
}
HttpWebResponse httpResponse = http.GetResponse() as HttpWebResponse;
// Probably want to inspect the http.Headers here first
http = WebRequest.Create(url2) as HttpWebRequest;
http.CookieContainer = new CookieContainer();
http.CookieContainer.Add(httpResponse.Cookies);
HttpWebResponse httpResponse2 = http.GetResponse() as HttpWebResponse;
Stream newStream = http.GetRequestStream(); //open connection
newStream.Write(dataBytes, 0, dataBytes.Length); // Send the data.
newStream.Close();
string sourceCode;
HttpWebResponse getResponse = (HttpWebResponse)http.GetResponse();
using (StreamReader sr = new StreamReader(getResponse.GetResponseStream()))
{
sourceCode = sr.ReadToEnd();
}
Response.Write(sourceCode);
}
You're creating a new request object here:
http = WebRequest.Create(url2) as HttpWebRequest;
Keep in mind that the default HTTP verb used is GET. Then you try to open the request stream here:
Stream newStream = http.GetRequestStream();
This method is used to enable writing data to the request's content. However, GET requests don't have content. As you do in the code above the error, you'll need to use a different HTTP verb. POST is most common for this, and is what you're using above:
http.Method = "POST";
So just use a POST request again. (Assuming, of course, that's what the server is expecting. In any event, if the server is expecting content then it's definitely not expecting a GET request.)

c# Trouble with PUT request using Skydrive REST API

I'm trying to upload a file to SkyDrive via the REST API. I've been using the following code, but I keep getting a "(415) Unsupported Media Type." error:
var requestUriFile =
new StringBuilder("https://apis.live.net/v5.0/<folderid>/files/testfile.txt");
requestUriFile.AppendFormat("?access_token={0}", accessTokenM);
byte[] arr = System.IO.File.ReadAllBytes("C:\\temp\\testFile.txt");
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(requestUriFile.ToString());
request.Method = "PUT";
request.ContentType = "text/plain";
request.ContentLength = arr.Length;
Stream dataStream = request.GetRequestStream();
dataStream.Write(arr, 0, arr.Length);
dataStream.Close();
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
string returnString = response.StatusCode.ToString();
I've also tried using RestSharp to do this, but I'm running into a similar issue. When I run the below code, I get returned the exception "The provided Content-Type header 'multipart/form-data; boundary\u003d-----------------------------28947758029299' is not supported".
byte[] arr = System.IO.File.ReadAllBytes("C:\\temp\\testFile.txt");
var client = new RestClient("https://apis.live.net/v5.0/");
var request = new RestRequest(Method.PUT);
request.Resource = "<folderId>/files/testfile.txt?access_token=" + accessTokenM;
request.AddHeader("content-type", "text/plain;");
request.AddFile("filename", arr, "testfile.txt", "text/plain");
var responseIn = client.Execute(request);
What am I doing wrong here?
Ok, I solved it. Apparently all I need to do is leave the ContentType blank and it works. Thanks :)

Categories

Resources