HELP !
I'm trying to upgrade may program to support the new oAuth that Google uses in the AdWords.
Using my website I'm able to create an accessToken and an accessTokenSecret for my users and store it in my database.
My problem is when I try to make a soap request later with those credentials.
Which information do I need to save from the website part? so far I save only the accessToken and the accessTokenSecret. is there anything else?
How do I use the accessToken, accessTokenSecret and what ever else I've saved in order to make a SOAP requests? (please be as "low level" as you can, "just use them in the request header" won't help me).
Some info on my process:
Not using the Client Library from Google (too much over head, and so far I didn't needed them).
Using the auto-generated SOAP code using VS2005 WSDL on the services I'm using.
C# code.
Any help would be highly appreciated.
Thanks!
=======================================================================================
As advised, I have extend the GetWebRequest in the following way:
protected override WebRequest GetWebRequest(Uri uri)
{
WebRequest request = base.GetWebRequest(uri);
String token = "XXXXXXXXXXX";//a valid token - changed for here.
String secret = "XXXXXXXXXXXX";//a valid secret - changed for here.
String consumerKey = "anonymous";
String consumerSecret = "anonymous";
String sigMet = "HMAC-SHA1";
String oauth_timestamp = ((DateTime.UtcNow.Ticks - new DateTime(1970, 1, 1).Ticks) / (1000 * 10000)).ToString();
String oauth_nonce = Guid.NewGuid().ToString();
Parameter[] paramArray = new Parameter[]{
new Parameter("oauth_consumer_key", consumerKey),
new Parameter("oauth_token", token),
new Parameter ("oauth_signature_method", sigMet),
new Parameter ("oauth_timestamp", oauth_timestamp),
new Parameter ("oauth_nonce", oauth_nonce)
};
String oauth_signature = CreateHMACSHA1Signature(
request.Method,
uri,
paramArray,
consumerSecret,
secret
);
request.Headers.Add(
"Authorization: OAuth " +
"realm=\"" + "https://www.google.com/" + "\"," +
"oauth_consumer_key=\"" + Parameter.EncodeParameterString(consumerKey) + "\"," +
"oauth_token=\"" + Parameter.EncodeParameterString(token) + "\"," +
"oauth_signature_method=\"" + Parameter.EncodeParameterString(sigMet) + "\"," +
"oauth_signature=\"" + Parameter.EncodeParameterString(oauth_signature) + "\"," +
"oauth_timestamp=\"" + Parameter.EncodeParameterString(oauth_timestamp) + "\"," +
"oauth_nonce=\"" + Parameter.EncodeParameterString(oauth_nonce) + "\""
);
return request;
}
the function CreateHMACSHA1Signature is the same one used to with OAuthGetRequestToken and OAuthAuthorizeToken just fine. but when used with the SOAP I'm getting the following error:
System.Web.Services.Protocols.SoapException: AuthenticationError.OAUTH_TOKEN_HEADER_INVALID # Service[ServicedAccountService.get]
Any idea why it is?
I've answered this question here in the context of the .NET client library at Google Ads API, C#, SOAP request with new oAuth 1.0?. But to answer your question in a NoClientLibrary context,
You just need the consumer key in addition to OAuth access key and secret.
You need to sign the request as if you were requesting a normal OAuth protected resource. Then put the signature in Authorization HTTP header (not the SOAP header) of your SOAP web request. However, getting hold of the underlying HttpWebRequest for a SOAPHttpClientProtocol object is not that straightforward. You need to extend SOAPHttpClientProtocol object, override the protected GetWebRequest method and set your OAuth headers at this stage: Something like:
protected override WebRequest GetWebRequest(Uri uri) {
WebRequest request = base.GetWebRequest(uri);
string oAuthHeader = SignTheRequestAndGetTheOAuthHeader(request);
if (!string.IsNullOrEmpty(oAuthHeader)) {
request.Headers["Authorization"] = oAuthHeader;
}
return request;
}
This also means that you have to manually modify the autogenerated code to change the base class of your stub service classes, something you are not going to enjoy much in the long run. Also, in case you don't know how to normally request an OAuth protected resource, the relevant documentation is at http://oauth.net/core/1.0/#anchor13.
Now, this is something that has been taken care of for you in the .NET client library. The library is not that difficult to use, there are enough wiki articles at http://code.google.com/p/google-api-adwords-dotnet/wiki to guide you. I recommend that you use the .NET client library, but in case you choose not to do so, here's a list of pitfalls you should be aware of when taking the NoClientLibrary route: http://code.google.com/p/google-api-adwords-dotnet/wiki/NoClientLibrary.
I also wanted to mention that AdWords API official discussion forum is at http://groups.google.com/group/adwords-api?pli=1, and I frequently answer developer questions there. If you have any followup questions, feel free to ask there and I'll be happy to answer your questions.
Cheers,
Anash
SUCCESS !!!
I finely found what was wrong, and it was only by a chance.
when creating the signature I've used the request.method for the method parameter.
The problem with this is that at this moment the method is "GET" but the SOAP mechanisim will change it to "POST" (so it can pass the SOAP parameters) this cause my signature to not work.
the only fix I needed to do is change:
String oauth_signature = CreateHMACSHA1Signature(
request.Method,
...
)
to:
String oauth_signature = CreateHMACSHA1Signature(
"POST",
...
)
Related
My WPF desktop application (C#) is attempting to read the user's Outlook emails through the Microsoft Graph API. I am stuck in the authentication process; I've already received an authentication code and now I'm trying to get an access token from Azure but keep getting a HTTP 400 error code when sending out the request for the access token:
/**** Auth Code Retrieval ****/
string authCodeUrl = "https://login.microsoftonline.com/common/oauth2/authorize";
authCodeUrl += "?client_id" = clientId;
authCodeUrl += "&redirect_uri=" + redirectUri;
authCodeUrl += "&response_type=code";
authCodeUrl += "&resource=https%3A%2F%2Fgraph.microsoft.com%2F";
Process.start(authUrl); // User logs in, we get the auth code after login
string code = "......"; // Hidden for this post
/**** Access Token Retrieval ****/
string tokenUrl = "https://login.microsoftonline.com/common/oauth2/token"
string content = "grant_type=authorization_code";
content += "&client_id=" + clientId;
content += "&resource=https%3A%2F%2Fgraph.microsoft.com%2F";
content += "&code=" + code;
content += "&redirect_uri=" + redirectUri;
WebRequest request = WebRequest.Create(tokenUrl);
request.ContentType = "application/x-www-form-urlencoded";
byte[] data = Encoding.UTF8.GetBytes(content);
request.ContentLength = data.Length;
request.Method = "POST";
try
{
using (Stream stream = request.GetRequestStream())
{
stream.Write(data, 0, data.Length);
}
WebResponse response = request.GetResponse(); // This throws exception
}
catch (Exception error) // This catches the exception
{
Console.WriteLine(error.Message); // Outputs 400, bad request
}
The above is the code used to retrieve the auth code followed by the attempt to retrieve the access token. We do not have a client_secret because secrets are only for Web applications and this is a native desktop WPF application. I have read that this isn't an issue though. I have followed many tutorials and official docs online, mainly the official Graph authorization doc and I still cannot figure out what I am doing wrong. Any help would be greatly appreciated, thank you.
I used fiddler to debug the request and I found the full error message: The user or administrator has not consented to use the application. I googled this message for a bit and found some stack articles and github issue threads that lead me to the solution: my request had been using "common", in the base URL, as the tenant ID when actually I needed to use my Azure tenant ID which I acquired through this answer on stack. My new base URL for the authentication requests now looks like:
https://login.microsoftonline.com/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/oauth2/authorize
where "xxxx-....xxx" would be replaced by your Azure tenant id!
If you don't use a client secret, then you need to configure your tenant to support implicit grant flow. You can follow the directions from this blog post to perform / validate the configuration. This requires using the Azure management portal to download, modify the app manifest, and upload it.
Alternatively, and possibly a better strategy, is to switch your code over to using the converged v2.0 authentication endpoints. It allows management of your application using the new app registration portal and nicely supports implicit flow and dynamic scopes. You can find more information about the actual authentication flow here. It isn't far from what you are doing now and requires only a few small tweaks.
If you are still having issues after this, please reach out again. A fiddler / network trace would be very helpful. Also, the detailed message inside the exception would also be very helpful.
I am trying to post a WPF form to my server, but I keep getting a 401 unauthorized response, even though I am sending the correct details.
This is my c# code
// Send the ComputerSettings to the API
String _Url = this.ApiUrl + "/api/hospitals/settings.xml";
String _Parameters = "";
_Parameters += "access_token=" + Authentication.AccessToken;
_Parameters += "&hospital_id=" + txtHospital.Text;
_Parameters += "&username=" + HttpUtility.UrlEncode(txtUsername.Text);
_Parameters += "&password=" + HttpUtility.UrlEncode(txtPassword.Password);
Debug.WriteLine(_Url + "?" + _Parameters);
WebClient _WebClient = new WebClient();
_WebClient.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
_WebClient.Encoding = System.Text.Encoding.UTF8;
_WebClient.UploadString(_Url, _Parameters);
When I run this from Visual Studio the Server returns a 401 unauthorized. But when I copy the url from Debug into into a REST Chrome Client (I use DHC in case that is important) then POST from there, the request works as expected.
My best guess is that Visual Studio is encoding the url parameters in an unexpected way. But I can't figure out what it is doing that is different. I also can't see a way to inspect the response contents, which would allow me to dump the data that the server is seeing into the response and debug it. I've tried things like
_ResponseString = _WebClient.UploadString(_Url, _Parameters);
Debug.WriteLine(_ResponseString);
But the exception is thrown before that Debug line, and when I inspect the Exception, the response has no contents.
edit:
I see my mistake, I'm sending the parameters as a query string in my REST client, but as request parameters from Visual Studio. The fix (for this example) is to change the UploadString call to
_WebClient.UploadString(_Url + "?" + _Parameters, "");
Just to make the solution to this more visible I'm going to post my edit as an answer
edit: I see my mistake, I'm sending the parameters as a query string
in my REST client, but as request parameters from Visual Studio. The
fix (for this example) is to change the UploadString call to
_WebClient.UploadString(_Url + "?" + _Parameters, "");
instead of
_WebClient.UploadString(_Url, _Parameters);
I am trying to connect to a web service from Lockheed Martin located here. I have looked at other examples and am using the following code to try and establish a connection. All I want to know at this point is if I have established a connection and been authorized but I repeatedly get an exception saying
Unauthorized at System.Net.HttpWebRequest.GetResponse()
. Am I setting up the web request and response correctly? Is there a different method that would simply let me know if I've successfully connected?
try
{
//Connect to the Lockheed Martin web client
WebRequest client = WebRequest.Create("https://www.elabs.testafss.net/Website2/ws");
string username = "username";
string password = "password";
string credentials = Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes(username + ":" + password));
client.Headers.Add("Authorization", "Basic " + credentials);
WebResponse response = client.GetResponse();
Console.WriteLine(((HttpWebResponse)response).StatusDescription);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
Probably your user / password is incorrect, looking at the documentation of the web service, your code is reproducing the exactly same hash that is in following sample:
Authentication - Basic Auth
Authentication is performed using the Basic Auth protocol. An authorization header is supplied with every web service request. This is sometimes called pre-emptive authentication. The header looks like this:
Authorization: Basic Vendor_ID:Vendor_Password
where the Vendor_ID:Vendor_Password string is converted to Base64.
Example
Authorization: Basic JoesFlightServices:SecretPW
Converted to Base64:
Authorization: Basic Sm9lc0ZsaWdodFNlcnZpY2VzOlNlY3JldFBX
Note that conversion to Base64 does not ensure the information will be private. We use HTTPS to encrypt the entire HTTP message including the headers.
Source
I'm using Trello's Developer API's implementation of OAuth to post stuff to a list.
I've successfully made a request and got my oauth_token and oauth_token_secret back from https://trello.com/1/OAuthGetRequestToken
But when I call https://trello.com/1/OAuthAuthorizeToken, passing the oauth_token that I've just received, I get a response of 'App not found'.
Can anyone help?
EDIT: Here's what I'm getting back from https://trello.com/1/OAuthGetRequestToken
oauth_token=8d0e43fd0cc67726567d49ae5e818852&oauth_token_secret=[secret]
And here's the Authorization header I'm sending (escaped in C#)
"OAuth oauth_version=\"1.0\", oauth_signature_method=\"HMAC-SHA1\", oauth_nonce=\"8335006\", oauth_timestamp=\"1414663625\", oauth_consumer_key=\"9612eaca23c7bdd3eca60dc8c2a8159c\", oauth_signature=\"M6sLyyfHGYXOtQnLJexDx96kbFo=\", oauth_token=\"8d0e43fd0cc67726567d49ae5e818852\""
Am I doing something wrong or is this an error on Trello's end?
EDIT: I'm using RestSharp to call the Trello API, as below:
var client = new RestSharp.RestClient("https://trello.com/");
var request = new RestSharp.RestRequest("1/OAuthAuthorizeToken", Method.GET);
EDIT: Here's the complete RestSharp code:
var client = new RestSharp.RestClient("https://trello.com/");
var request = new RestSharp.RestRequest("1/OAuthAuthorizeToken", Method.GET);
Uri uri = new Uri(string.Format("{0}/{1}", client.BaseUrl, request.Resource));
string authHeader = GenerateAuthorizationHeader(uri);
//This is the output of GenerateAuthorizationHeader()
//string authHeader = "OAuth oauth_version=\"1.0\", oauth_signature_method=\"HMAC-SHA1\", oauth_nonce=\"8335006\", oauth_timestamp=\"1414663625\", oauth_consumer_key=\"9612eaca23c7bdd3eca60dc8c2a8159c\", oauth_signature=\"M6sLyyfHGYXOtQnLJexDx96kbFo=\", oauth_token=\"8d0e43fd0cc67726567d49ae5e818852\"";
request.AddHeader("Authorization", authHeader);
The GenerateAuthorizationHeader method uses OAuth.OAuthBase to generate the TimeStamp and Signature for the OAuth request.
Looks like it might be a trello problem...
this user, had the wrong key by the sounds of things.
are you 100% sure that the key is correct.
Getting "App not found" from Trello Authentication
I had the same problem, the thing here is that OAuth is version 1.0
When you get the token and token secret from the first call you have to make your user to visit https://trello.com/1/OAuthAuthorizeToken not you.
In your case you have to redirect your user to https://trello.com/1/OAuthAuthorizeToken?oauth_token=8d0e43fd0cc67726567d49ae5e818852&scope=read,write,account
He will get a page where he can Allow the access. Then you will get a verification code in the page after the authorization to continue with your process (GetAccessToken).
You can try this as a test, in a real application you have to specify a callback url and an application name in the OAuthAuthorizeToken call.
I am struggling to call APIs hosted in Google Cloud https://apis-explorer.appspot.com/apis-explorer/?base=https%3A%2F%2Finnovative-glass.appspot.com%2F_ah%2Fapi#p/mirror/v1/
Up to my understanding, APIs are exposed as REST service. I need to make rest service call from .net application.
I have done OAuth Authentication. I am passing access_token as per the guidance given https://developers.google.com/accounts/docs/OAuth2WebServer
My Code:
UriBuilder uriBuilder = new UriBuilder("https://innovative-glass.appspot.com/_ah/api/mirror/v1/timeline");
string userId = Session["userId"] as string;
var state = Utils.GetStoredCredentials(userId);
NameValueCollection queryParameters = HttpUtility.ParseQueryString(uriBuilder.Query);
queryParameters.Set("access_token", state.AccessToken);
uriBuilder.Query = queryParameters.ToString();
var request = (HttpWebRequest)WebRequest.Create(uriBuilder.ToString());
request.Method = "GET";
var response = (HttpWebResponse)request.GetResponse();
I am getting UnAuthorized exception.
Is my understanding is right? Am I doing right way?
It seems that cloud endpoints don't use the Google API default of accepting access_token as query parameter. According to the Discovery document the equivalent query parameter is oauth_token so it should work with:
queryParameters.Set("oauth_token", state.AccessToken);
Alternatively (which in my opinion is the better solution) you can also set the Authorization header of the request instead of adding the token as query parameter:
request.Headers.Add("Authorization", "Bearer " + state.AccessToken);
Where are you getting the AccessToken from, and are you sure it is still a valid token? Remember that access tokens expire about an hour after being generated, although can be revoked earlier.
Clicking on the sign-in button at innovative-glass.appspot.com gives me an origin mismatch error, so it looks like you may also have a configuration issue.
Have you been able to get it to work using just the API Explorer?