I've implemented a c# app which creates calendar events using the calendar API.
In order to keep the calendar in sync with our local db I've created a watch on the calendar. The following code does this and, as far as I can see, a watch is created.
Channel watchChannel = new Channel()
{
Id = ConfigurationManager.AppSettings["GOOGLE_CALENDAR_WATCH_NAME"],
Type = "web_hook",
Address = ConfigurationManager.AppSettings["GOOGLE_CALENDAR_SYNC_TRIGGER_CALLBACK_URL"],
Expiration = (unixTimestamp + NINETY_DAYS_IN_SECONDS) * 1000 //milliseconds
};
try
{
logger.Debug("Creating calendar watch with the name " +
ConfigurationManager.AppSettings["GOOGLE_CALENDAR_WATCH_NAME"] + " for calendar with id " + remoteCalendarId);
Channel returnChannel = service.Events.Watch(watchChannel, remoteCalendarId).Execute();
My problem is that the callback URL isn't getting called (i have confirmed ownership of the domain and authenticated it for the user, that shouldn't be the issue).
How do I debug this? Is there anywhere I can look at the attempts google is
making to call the callback URL?
I say that as far as I can see everything is created ok, but maybe I'm wrong, which property in the
returnChannel should I be looking at?
Is there any way to list all created watches/channels for a particular calendar? If so, which API is that exposed through?
04.04 - A bit more information:
These are the parameters set on the outgoing call (watchChannel) and return-object (returnChannel).
watchChannel
Address "https://a.domain.com/api/schedule/syncDbAndSchedule"
ETag = null
Expiration = 1491309746000
Id = "my_id_watch_dev"
Kind = null
Params__ = null
Payload = null
ResourceId = null
ResourceUri = null
Token = null
Type = "web_hook"
returnChannel
Address = null
ETag = null
Expiration = 1491309746000
Id = "my_id_watch_dev"
Kind = "api#channel"
Params__ = null
Payload = null
ResourceId = "t6uxfXzXXXXXXXXXXsC9ZEqMdzU"
ResourceUri = "https://www.googleapis.com/calendar/v3/calendars/a.domain.com_nsqpp2XXXXXX93olf0ul40sphg#group.calendar.google.com/events?maxResults=250&alt=json"
Token = null
Type = null
Looking at it again I've got a few more questions:
Can I be sure the above returned a HTTP-200 response? The client-libs seem to abstract away the actual request/response and I can't find any trace of it in the objects I'm looking at. As the 4xx responses I've gotten have been transformed into exceptions that's what I'd expect for any non-200 response but can I be sure of that?
Is there really no way to track the attempts google is making whilst calling the callback URL? Since there seems to be no way to get a hold of a created watch it kind of surprises me there is no GUI where I can track this. Makes hunting for errors really hard.
Code to authenticate
I use the following code to authenticate the system user and then make it act in the guise of a 'normal' non-system account (since a pure system-account seemed a tricky way to go if you actually wanted to look at the calendar too).
ServiceAccountCredential credential =
GoogleCredential.FromJson(GOOGLE_SYSTEM_USER_AUTH_INFORMATION)
.CreateScoped(Scopes)
.UnderlyingCredential as ServiceAccountCredential;
var userField =
typeof(ServiceAccountCredential).GetField("user", BindingFlags.NonPublic | BindingFlags.Instance);
userField?.SetValue(credential, GOOGLE_CALENDAR_USERNAME); //Act in the guise of the normal user GOOGLE_CALENDAR_USERNAME
service = new CalendarService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = ApplicationName,
});
on a whim I visited the ResourceURI returned. It gives me
{
"error": {
"errors": [
{
"domain": "usageLimits",
"reason": "dailyLimitExceededUnreg",
"message": "Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup.",
"extendedHelp": "https://code.google.com/apis/console"
}
],
"code": 403,
"message": "Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup."
}
}
Is
this the status for the watch? If so, why didn't I get a 403 whilst creating it?
Am I really Unautenticated or is it just that my request through a browser is?
The callback url must be https (certificate) otherwise it will not be called!
Related
Just migrated to Stripe.com. I am creating a checkout session programmatically. See code snippet below. When I test, the User.Identity.GetUserId() comes back with a value and it is sent to stripe. However, when end user completes the payment, Stripe.com is not sending back the client_reference_id (it is null) in the event checkout.session.completed that I am listening to.
I get back my client_reference_id when I do payment links (send via querystring)
What am I doing wrong?
[HttpPost]
[AllowAnonymous]
public ActionResult SendToCheckout(ProcessPaymentViewModel model)
{
StripeConfiguration.ApiKey = _apiSecret;
var options = new SessionCreateOptions
{
ClientReferenceId = User.Identity.GetUserId(),
SuccessUrl = ConfigurationManager.AppSettings["BaseUrl"] + "/PaymentComplete",
CancelUrl = ConfigurationManager.AppSettings["BaseUrl"] + "/Subscribe",
LineItems = new List<SessionLineItemOptions>
{
new SessionLineItemOptions
{
Price = model.PriceId,
Quantity =long.Parse(model.Quantity)
},
},
Mode = "payment",
};
var service = new SessionService();
var session = service.Create(options);
return Redirect(session.Url);
}
reviewed stripe.com documentation. It appears I am setting it correctly. The other questions posted is one is really not answered and the other one says it should be in that webhook event. I dumped the values and it should client_reference_id: null
The code you shared looks correct and it's almost certain that you are not setting a value when you think you are.
The best path forward is to hardcode a value in your code and you should see that it works as expected and that the problem is the value you put in. What I would do is hardcode AAAA, confirm it's there, and then concat AAAA and the value in your variable and another string like AAAA-<userid>-BBBB and see that you get AAAA--BBBB because your string is null or empty.
This isn't a Stripe bug, that feature works as expected and is used widely but I've tested it quickly to confirm.
You can also look at the response on the Session creation after your code and just print session.ClientReferenceId and see that it's null right now.
I am trying to get dynamic link stats via Dynamic Links Analytics API with the method FirebaseDynamicLinksService.V1.GetLinkStats()... I was able to create a short link easily and it works... But the problem is to get the stats about this dynamic link.
I got 403:
"Google.Apis.Requests.RequestError
The caller does not have permission [403]
Errors [Message[The caller does not have permission] Location[ - ] Reason[forbidden] Domain[global]]"
Is there something I am missing? I tried to follow this https://firebase.google.com/docs/reference/dynamic-links/analytics
My code basically looks like this:
var googleCredential = GoogleCredential.FromFile(shortLinkServiceConfiguration.KeyFileName).CreateScoped($"https://www.googleapis.com/auth/firebase");
var dynamicLinksService = new FirebaseDynamicLinksService(new Google.Apis.Services.BaseClientService.Initializer
{
HttpClientInitializer = googleCredential,
ApplicationName = shortLinkServiceConfiguration.ApplicationName
});
var request = dynamicLinksService.ShortLinks.Create(createShortDynamicLinkRequest);
request.AccessToken = googleCredential.UnderlyingCredential.GetAccessTokenForRequestAsync().Result;
// This works and I get the short link
var response = request.Execute();
var secondRequest = dynamicLinksService.V1.GetLinkStats(response.ShortLink);
secondRequest.AccessToken = googleCredential.UnderlyingCredential.GetAccessTokenForRequestAsync().Result;
secondRequest.DurationDays = 7;
// This does not work and I get 403
var secondResponse = secondRequest.Execute();
So with the help in here: https://github.com/googleapis/google-api-dotnet-client/issues/1448
The problem was solved with addition of "Firebase Grow Viewer" role in the service account...
I am using Google Plus API for .Net for implementing sharing on google plus using WebAuthenticationBroker. It returns a token after the user gets logged in but when I send a moments post request it returns error 401.
My code on clicking on image is
String GoogleURL = "https://accounts.google.com/o/oauth2/auth?client_id=xxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com&redirect_uri=http://www.google.com&response_type=code&scope=" + Uri.EscapeDataString("https://www.googleapis.com/auth/plus.stream.write https://www.googleapis.com/auth/plus.login https://www.googleapis.com/auth/plus.login");
PlusService service = new PlusService();
System.Uri StartUri = new Uri(GoogleURL);
System.Uri EndUri = new Uri("https://accounts.google.com/o/oauth2/approval?");
WebAuthenticationBroker.AuthenticateAndContinue(new Uri(GoogleURL), EndUri);
now when it returns after authenticating I have called method upload on google in continue which is as follows--
PlusService service = new PlusService();
Moment body = new Moment();
ItemScope itemScope = new ItemScope();
itemScope.Id = "replacewithuniqueforaddtarget";
itemScope.Image = "http://www.google.com/s2/static/images/GoogleyEyes.png";
itemScope.Type = "";
itemScope.Description = "The description for the action";
itemScope.Name = "An example of add activity";
body.Object = itemScope;
body.Type = "http://schema.org/AddAction";
MomentsResource.InsertRequest insert =
new MomentsResource.InsertRequest(
service,
body,
"me",
MomentsResource.InsertRequest.CollectionEnum.Vault);
Moment wrote = insert.Execute();
But it returns exception 401. The code to post I found on Google Console Help. Can somebody help in this?
I finally found out that google APIs are not directly open to third party developers and it just made my case void and had to use HTTP method for this. Thanks #DalmTo for answering.
I am using the Microsoft.AspNet.Mvc.Facebook NuGet package. I would like to exchange a regular token for the extended access token (the one that replaced the offline_access permission).
From Googling around I found the URL should be in this format:
https://graph.facebook.com/oauth/access_token?
client_id=[APP_ID]&
client_secret=[APP_SECRET]&
grant_type=fb_exchange_token&
fb_exchange_token=[EXISTING_ACCESS_TOKEN]
So I use the following code:
var longToken = await context.Client.PostTaskAsync("/oauth/access_token",
new
{
client_id = fbApp.AppId,
client_secret = fbApp.AppSecret,
grant_type = "fb_exchange_token",
fb_exchange_token = context.AccessToken
});
This returns a null. No error or anything. Just a null value.
Edit: Also tried the following, which also did not work. But a GET seems more logical than a POST anyway.
dynamic result = context.Client.Get("oauth/access_token",
new
{
client_id = fbApp.AppId,
client_secret = fbApp.AppSecret,
grant_type = "fb_exchange_token",
fb_exchange_token = context.AccessToken
});
var longToken = result.access_token as string;
I have successfully done this as a GET request, not a POST :) Just put the necessary parameters into the URL and request it as a GET request and the response returns the long term access token.
EDIT
When you get the result from this, you should parse the query string first (am not sure in C# but maybe you could use this link: http://msdn.microsoft.com/en-us/library/ms150046(v=vs.110).aspx).
After that try to get the access_token property and I got it right on my end. I was doing it in node.js though, but essentially the same flow.
So i've been using Linq-To-Twitter to add Twitter Integration to my Windows 8 Store App, Moreso for playing around with it, but i've come accross a problem. My current authentication codeblock is
var auth = new WinRtAuthorizer
{
Credentials = new LocalDataCredentials
{
ConsumerKey = "",
ConsumerSecret = ""
},
UseCompression = true,
Callback = new Uri("http://linqtotwitter.codeplex.com/")
};
if (auth == null || !auth.IsAuthorized)
{
await auth.AuthorizeAsync();
}
Which works great, unless I go into the authentication screen and click the back button on the top left, to exit authentication without supplying details. at which point i get a TwitterQueryException: Bad Authentication data at:
var timelineResponse =
(from tweet in twitterCtx.Status
where tweet.Type == StatusType.Home
select tweet)
.ToList();
Obviously because the Authentication Information was wrong, I'm trying to find a way to stop proceeding to the rest of the code if the authentication fails/is backed out.
I've tried simple boolean checks to no effect. I've been melting my brain over this for hours, so any help would be greatly appreciated. Thanks a bunch!
You can query Account.VerifyCredentials to ensure the user is logged in before performing any other operation. Here's an example:
const int BadAuthenticationData = 215;
var twitterCtx = new TwitterContext(auth);
try
{
var account =
(from acct in twitterCtx.Account
where acct.Type == AccountType.VerifyCredentials
select acct)
.SingleOrDefault();
await new MessageDialog(
"Screen Name: " + account.User.Identifier.ScreenName,
"Verification Passed")
.ShowAsync();
}
catch (TwitterQueryException tqEx)
{
if (tqEx.ErrorCode == BadAuthenticationData)
{
new MessageDialog(
"User not authenticated",
"Error During Verification.")
.ShowAsync();
return;
}
throw;
}
Your error handling strategy will differ from this, which is just a sample, but it shows you how to know that the error occurred and gives you the opportunity to react to the problem before resuming normal operation.
TwitterQueryException will include the Twitter error code in the ErrorCode property. It also sets Message to the error message that Twitter returns. InnerException provides the underlying exception with the original stack trace, which is often a WebException thrown because of the HTTP error code returned from Twitter.