This walk through/demonstration and instruction for requesting a token does not work. When I execute my code exactly as you have it and run it, I receive a 400 error every time, and this json response:
{
error: "invalid_grant"
}
https://developers.google.com/accounts/docs/OAuth2ServiceAccount#makingrequest
I have been trying now to get this to work for almost a week, and am not getting any useful help here, and I see lot of similar questions here unanswered.
Thanks, any help would be amazing!
Karl..
Here is the code I am using (which I've wrapped up a bit and I may need to reveal internal code). Note: I left in the strange \/ slashes ins the scope and aud props of the claim as I am trying another guys fix from Stack http://goo.gl/bt9lPj (that doesn't seem to be working either and I'm getting the exact same error)
var claimbuilder = new Stub.Jwt.ClaimsBuilder();
claimbuilder.Add("iss", "...#developer.gserviceaccount.com");
claimbuilder.Add("scope", "https:\\/\\/picasaweb.google.com\\/data\\/");
claimbuilder.Add("aud", "https:\\/\\/accounts.google.com\\/o\\/oauth2\\/token");
claimbuilder.Add("exp", (Stub.Jwt.Utility.UnixTime + (60 * 5)).ToString());
claimbuilder.Add("iat", Stub.Jwt.Utility.UnixTime.ToString());
string head = "{\"alg\":\"RS256\",\"typ\":\"JWT\"}";
var jwt = String.Format("{0}.{1}", head, claimbuilder.ClaimSet);
Console.WriteLine(jwt);
var certificate = new X509Certificate2(#"....-privatekey.p12", "notasecret", X509KeyStorageFlags.Exportable);
var token = new Stub.Jwt.JsonWebToken();
var jwtresult = token.Generate(head, claimbuilder.ClaimSet, certificate);
Console.WriteLine("jwt: {0}", jwtresult);
OAuth.Response resp = new OAuth.Response();
OAuth.Request auth = new OAuth.Request("https://accounts.google.com/o/oauth2/token");
auth.AddPostVar("grant_type", HttpUtility.UrlEncode("urn:ietf:params:oauth:grant-type:jwt-bearer")); // "authorization_code");
auth.AddPostVar("assertion", jwt);
auth.Go(resp);
Console.WriteLine(resp.OAuthTokenValue);
The code is only valid for a few minutes and after expired you will receive invalid_grant as response.
Could you paste here the JSON payload your code constructs? That'd make spotting issues easier.
Related
So using the following simple code to just test tweet to Twitter. I have signed up for the account and have all the pertinent info. The only thing I may be doing wrong is putting the wrong key/secret in the wrong area. Here is my Twitter dev setup:
This is my simple code:
function sendTweet(status) {
status = "Is this a cool tweet?";
var twitterKeys = {
TWITTER_CONSUMER_KEY: '**************************',
TWITTER_CONSUMER_SECRET: '**************************',
TWITTER_ACCESS_TOKEN: '**************************-**************************',
TWITTER_ACCESS_SECRET: '**************************',
};
var props = PropertiesService.getScriptProperties();
props.setProperties(twitterKeys);
var service = new Twitterlib.OAuth(props);
if (service.hasAccess()) {
var response = service.sendTweet(status);
if (response) {
Logger.log('Tweet ID ' + response.id_str);
} else {
// Tweet could not be sent
// Go to View -> Logs to see the error message
}
}
}
My consumer key/secret -> API Key and Secret below and my access token/secret -> Access Token and Secret below. I am seeing the following error which doesn't give me a lot to go on as far as errors and been fighting to figure this out for days.
Send tweet failure. Error was:
{"name":"Exception"}
options were:
{"method":"POST","payload":"status=Is%20this%20a%20cool%20tweet%3F","headers":{"Authorization":"OAuth oauth_consumer_key=\"**************************\", oauth_nonce=\"**************************\", oauth_signature=\"**************************%3D\", oauth_signature_method=\"HMAC-SHA1\", oauth_timestamp=\"1644456180\", oauth_token=\"**************************-**************************\", oauth_version=\"1.0\""},"escaping":false}
Any help or resources would be a huge help in figuring this out!! Thank you in advance.
phi
This turned out being I needed to turn on essential API access in the Twitter API Developer site. Once I turned that on, and retried, it was a success. Hope that helps anyone else.
I have written the code:
function getId(username) {
var infoUrl = "https://www.instagram.com/web/search/topsearch/?context=user&count=0&query=" + username
return parseInt(fetch(infoUrl)['users']);
}
function fetch(url) {
var ignoreError = {
"muteHttpExceptions": true
};
var source = UrlFetchApp.fetch(url, ignoreError).getContentText();
var data = console.log(source);
return data;
}
To get the userID of the username input.
The error corresponds to the line:
return parseInt(fetch(infoUrl)['users']);
I have tried differnt things but I cant get it to work. The url leads to a page looking like this:
{"users": [{"position": 0, "user": {"pk": "44173477683", "username": "mykindofrock", "full_n........
Where the numbers 44173477683 after the "pk": are what I am trying to get as an output.
I hope someone can help as I am very out of my depth, but I guess this is how we learn! :)
I was surprised that the endpoint you provided actually led to a JSON file. I would have thought that to access the Instagram API, you would need register a developer account with Facebook etc. Nevertheless, it does return a JSON by visiting in the browser. I suppose that it just shows the publicly available information on each user.
However, with Apps Script it seems like a different story. I visited:
https://www.instagram.com/web/search/topsearch/?context=user&count=0&query=user
In a browser and chose a random user id. Then I called it from Apps Script with UrlFetchApp:
function test(){
var username = "username7890543216"
var infoUrl = "https://www.instagram.com/web/search/topsearch/?context=user&count=0&query=" + username
var options = {
'muteHttpExceptions': true
}
var result = UrlFetchApp.fetch(infoUrl, options)
console.log(result.getResponseCode())
}
Which returns a 429 response. Which is a "Too Many Requests" response. So if I had to guess, I would say that all requests to this unauthenticated endpoint from Apps Script have been blocked. This is why when replacing the console.log(result.getResponseCode()) with console.log(result.getContentText()), you get a load of HTML (not JSON) part of it which says:
<title>
Page Not Found • Instagram
</title>
Though maybe its IP based. Try and run this code from your end, unless you get a response code of 200, it is likely that you simply can't access this information from Apps Script.
You are setting data to the return value of console.log(source) which is undefined. So no matter what the data is, you will get undefined.
Another thing to avoid is that fetch will not necessarily be hoisted because fetch is a built in function to make API calls.
I have a question about this create/Update leads API, http://developers.marketo.com/documentation/rest/createupdate-leads/.
There is no sample code for C# or JAVA. Only ruby available. So I have to try it by myself. But I always get null return from the response.
Here is my code:
private async Task<CreateLeadResponseResult> CreateLead(string token)
{
string url = String.Format(marketoInstanceAddress+"/rest/v1/leads.json?access_token={0}", token);
var fullUri = new Uri(url, UriKind.Absolute);
CreateLeadResponseResult createLeadResponse = new CreateLeadResponseResult();
CreateLeadInput input = new CreateLeadInput { email = "123#123.com", lastName = "Lee", firstName = "testtesttest", postCode = "00000" };
CreateLeadInput input2 = new CreateLeadInput { email = "321#gagaga.com", lastName = "Lio", firstName = "ttttttt", postCode = "00000" };
List<CreateLeadInput> inputList = new List<CreateLeadInput>();
inputList.Add(input);
inputList.Add(input2);
CreateLeadRequest createLeadRequest = new CreateLeadRequest() { input = inputList };
JavaScriptSerializer createJsonString = new JavaScriptSerializer();
string inputJsonString = createJsonString.Serialize(createLeadRequest);
using (var client = new HttpClient())
{
HttpResponseMessage response = await client.PostAsJsonAsync(fullUri.OriginalString, inputJsonString).ConfigureAwait(false);
// I can see the JSON string is in the message body in debugging mode.
if (response.IsSuccessStatusCode)
{
createLeadResponse = await response.Content.ReadAsAsync<CreateLeadResponseResult>();
}
else
{
if (response.StatusCode == HttpStatusCode.Forbidden)
throw new AuthenticationException("Invalid username/password combination.");
else
throw new ApplicationException("Not able to get token");
}
}
return createLeadResponse;}
//get null here.
Thank you.
-C.
The best way to debug this is to capture the exact URL, parameters and JSON that are submitted by your app and try submitting those manually via a tool like Postman (Chrome plug-in) or SOAP UI. Then you see the exact error message, which you can look up here: http://developers.marketo.com/documentation/rest/error-codes/. Based on that you can update your code. I don't know much about Java, but this is how I got my Python code to work.
Your example code was really helpful in getting my own implementation off the ground. Thanks!
After playing with it for a bit, I realized that the JavaScriptSerializer step is unnecessary since PostAsJsonAsync automatically serializes whatever object you pass to it. The double serialization prevents Marketo's API from processing the input.
Also, I agree with Jep that Postman is super helpful. But in the case of this error, Postman was working fine (using the contents of inputJsonString) but my C# code still didn't work properly. So I temporarily modified the code to return a dynamic object instead of a CreateLeadResponseResult. In debugging mode this allowed me to see fields that were discarded because they didn't fit the CreateLeadResponseResult type, which led me to the solution above.
I've been roughly searching over the internet for some answers to my problem, but I still couldn't figure out how to log in to a website properly.
Firstly, I'm going to explain what I've done until this moment.
» I opened this website: http://side.utad.pt/cursos/einformatica/ upon which I want to log in.
» After opening its souce code, I found the Url that the Login form posts to is:
https://side.utad.pt/side-secure3/login.pl
I tried to open it but an Internal Error came out so I tried to access that url without /login.pl instead but i don't have permission to. As I can't get this Url working, I thought about using the first link itself.
» By using tamper data extension(Firefox) I found that there are 3 post arguments: sessionid, username and password. Username and password are input by the user himself.
To get sessionid, I simply searched for it inside source code and took it from there:
String^ formUrl = "http://side.utad.pt/cursos/einformatica/";
String^ pageSource;
WebClient^ client = gcnew WebClient();
pageSource = client->DownloadString(formUrl);
delete client;
client = nullptr;int index = pageSource->IndexOf("sessionid");
int startIndex = index + 34;
String^ _sessionid = pageSource->Substring(startIndex, 32);
Until here, everything was fine apart from the Url problem.
» Started formatting all the data gathered(which I believe is the correct way):
String^ formParams;
// format data
formParams = "sessionid="+ _sessionid+"&username="+username+"&password="+password;
» After that, I started working with the "body" of the code:
WebRequest^ req = WebRequest::Create(formUrl);
// encode our data
array<Byte>^ bytes = System::Text::Encoding::ASCII->GetBytes(formParams);
req->ContentType = "application/x-www-form-urlencoded";
req->Method = "POST";
req->ContentLength = bytes->Length;
Stream^ os = req->GetRequestStream();
os->Write(bytes,0,bytes->Length);
os->Close();
Am I doing it correctly until here?
» I wanted to check if i'm logged in or not, so I thought about getting another source code, but this time on pos-login page(can be accessed without logging in but we're always carried to that page after logging in):
// this code is added below os->Close();
WebResponse^ resp = req->GetResponse();
String^ cookieHeader;
cookieHeader = resp->Headers["Set-cookie"];
WebRequest^ getRequest = WebRequest::Create("http://side.utad.pt/cursos/einformatica/principal"); // Exception 1
getRequest->Headers->Add("Cookie", cookieHeader);
WebResponse^ getResponse = getRequest->GetResponse();
StreamReader^ sr = gcnew StreamReader(getRequest->GetRequestStream()); // Exception 2
pageSource = ""; // reset
pageSource = sr->ReadToEnd();
Firstly, the first line does raise an exception - most of the times - but I don't know the cause: 'The server commited a protocol violation Section=ResponseStatusLine'
Secondly and lastly, when that line doesn't raise an exception, this does(cannot send a content-body with this verb-type)
StreamReader^ sr = gcnew StreamReader(getRequest->GetRequestStream());
Any ideas to get this working?
I think that the problem here is related to the cookies. I might have not saved them properly..
Thanks
I am trying to to use the latest version of the Report API using OAuth 2. It doesn't appear that there are many people using this version yet, so it has been really hard to find examples.
I have a refresh token, which I am using to generate an access token.
private AnalyticsService getAnalyticsService()
{
AuthorizationServerDescription description = new AuthorizationServerDescription();
description.TokenEndpoint = new Uri(login.TokenEndpoint);
description.AuthorizationEndpoint = new Uri(login.AuthorizationEndpoint);
WebServerClient client = new WebServerClient(description, login.ClientId, login.ClientSecret);
OAuth2Authenticator<WebServerClient> authenticator = new OAuth2Authenticator<WebServerClient>(client, authenticate);
AnalyticsService service = new AnalyticsService(authenticator);
return service;
}
private IAuthorizationState authenticate(WebServerClient client)
{
string[] scopes = new string[] { login.ScopeUrl }; // not sure if this is necessary
IAuthorizationState state = new AuthorizationState(scopes) { RefreshToken = login.RefreshToken };
client.RefreshToken(state);
return state;
}
This appears to be working just fine:
{
"access_token" : "ya29.AHES6ZQy67SSLHWJWGWcLbLn69yKfq59y6dTHDf4ZoH9vHY",
"token_type" : "Bearer",
"expires_in" : 3600
}
However, when I do a request, I am getting an error. For example, here
is a query that results in an error:
AnalyticsService service = getAnalyticsService();
ManagementResource.ProfilesResource.ListRequest request = service.Management.Profiles.List("~all", "~all");
return request.Fetch();
This is the error I get:
{"error":{"errors":[{"domain":"global","reason":"authError","message":"Invalid
Credentials","locationType":"header","location":"Authorization"}],"code":401,"message":"Invalid
Credentials"}}
I have tried other queries, providing valid profile IDs. However, I am
always getting a 401 error, saying I'm not authorized. I am having
trouble finding examples where people are using this code. It could be
something simple like a bad URL or something. Unfortunately, I have no
way to telling. It seems strange that I can get an access token, but I
can't seem to perform any queries.
With OAuth 2, the scope changed from:
https://www.google.com/analytics/feeds/
to:
https://www.googleapis.com/auth/analytics.readonly
You are getting the authentication error because you were trying to get access without the proper scope.
Quick and easy fix.