Google API OAuth2, Service Account, “error” : “invalid_grant”

后端 未结 3 1149
离开以前
离开以前 2020-12-04 01:48

I\'m trying to use service account to sync calendars from Dynamics CRM software to Google. During this I faced lack of documentation on google API for .net, especially regar

相关标签:
3条回答
  • 2020-12-04 02:03

    After some investigations I found, that Google API does not work as expected with your personal account @gmail.com. You should have organization domain account in Google in format you@your_organisation_domain

    Then, what is also pretty confusing, there is documentation at Google Drive API page, with "Delegate domain-wide authority to your service account" section not mentioned at Calendar API page. There are 7 steps in the section, are required to be done.

    BTW with personal account administration site admin.google.com is even unavailable. So it's impossible to perform these 7 steps with @gmail.com account.

    Then, when client is authorised in Google Apps Admin Console > Security > Advanced settings > Manage OAuth Client access the code starts to work.

    There is a code that works for me:

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Security.Cryptography.X509Certificates;
    using Google.Apis.Calendar.v3;
    using Google.Apis.Calendar.v3.Data;
    using Google.Apis.Auth.OAuth2;
    using Google.Apis.Services;
    
    namespace CrmToGoogleCalendar
    {
        class Program
        {
    
            static void Connect()
            {
                Console.WriteLine("Calendar via OAuth2 Service Account Sample");
    
                var certificate = new X509Certificate2("My MC Project-3f38defdf4e4.p12", "notasecret", X509KeyStorageFlags.Exportable);
                var serviceAccountEmail = "795039984093-c6ab1mknpediih2eo9cb70mc9jpu9h03@developer.gserviceaccount.com";
                var userAccountEmail = "me@testdomain.com"; 
                var credential = new ServiceAccountCredential(new ServiceAccountCredential.Initializer(serviceAccountEmail) 
                    {
                        User = userAccountEmail,
                        Scopes = new[] { CalendarService.Scope.Calendar }
                    }
                    .FromCertificate(certificate));
    
                var service = new CalendarService(new BaseClientService.Initializer()
                {
                    ApplicationName = "Test calendar sync app",
                    HttpClientInitializer = credential
    
                });
    
                /* Get list of calendars */
                var calList = service.CalendarList.List().Execute().Items;
                var myCalendar = calList.First(@c => @c.Id == userAccountEmail);
    
                /* CREATE EVENT */
                var event1 = new Event()
                    {
                        Kind = "calendar#event",
                        Summary = "Calendar event via API",
                        Description = "Programmatically created",
                        Status = "confirmed",
                        Organizer = new Event.OrganizerData() {
                            Email = userAccountEmail
                        },
                        Start = new EventDateTime()
                            {
                                DateTime = DateTime.Now.AddDays(1)
                            },
                        End = new EventDateTime()
                        {
                            DateTime = DateTime.Now.AddDays(1).AddHours(1)
                        },
                        ColorId = "6",
                        Reminders = new Event.RemindersData()
                            {
                                UseDefault = false,
                                Overrides = new List<EventReminder>(
                                    new [] {
                                        new EventReminder()
                                            {
                                                Method = "popup",
                                                Minutes = 60
                                            }
                                    })
                            }
                    };
    
                event1 = service.Events.Insert(event1, myCalendar.Id).Execute();
                Console.WriteLine("Created event Id: {0}", event1.Id);
    
    
                /* ENLIST EVENTS */
                Console.WriteLine("calendar id={0}", myCalendar.Id);
                var events = service.Events.List(myCalendar.Id).Execute();
                foreach (var @event in events.Items)
                {
                    Console.WriteLine("Event ID: {0}, ICalUID: {1}", @event.Id, @event.ICalUID);
                    Console.WriteLine("  Name: {0}", @event.Summary);
                    Console.WriteLine("  Description: {0}", @event.Description);
                    Console.WriteLine("  Status: {0}", @event.Status);
                    Console.WriteLine("  Color: {0}", @event.ColorId);
                    Console.WriteLine("  Attendees: {0}", @event.Attendees == null ? "" : @event.Attendees.Select(a => a.Email).ToString());
                    Console.WriteLine("  Kind: {0}", @event.Kind);
                    Console.WriteLine("  Location: {0}", @event.Location);
                    Console.WriteLine("  Organizer: {0}", @event.Organizer.Email);
                    Console.WriteLine("  Recurrence: {0}", @event.Recurrence == null ? "no recurrence" : String.Join(",", @event.Recurrence));
                    Console.WriteLine("  Start: {0}", @event.Start.DateTime == null ? @event.Start.Date : @event.Start.DateTime.ToString());
                    Console.WriteLine("  End: {0}", @event.End.DateTime == null ? @event.End.Date : @event.End.DateTime.ToString());
                    Console.WriteLine("  Reminders: {0}", @event.Reminders.UseDefault.Value ? "Default" : "Not defailt, " + 
                        (@event.Reminders.Overrides == null ? "no overrides" : String.Join(",", @event.Reminders.Overrides.Select(reminder => reminder.Method + ":" + reminder.Minutes)))
                        );
                    Console.WriteLine("=====================");
                }
    
                Console.ReadKey();
            }
    
    
            static void Main(string[] args)
            {
                Connect();
            }
        }
    }
    

    The output produced looks so:

    Calendar via OAuth2 Service Account Sample
    Created event Id: jkits4dnpq6oflf99mfqf1kdo0
    calendar id=me@testdomain.com
    Event ID: 1logvocs77jierahutgv962sus, ICalUID: 1logvocs77jierahutgv962sus@google.com
      Name: test event
      Description: test description2
      Status: confirmed
      Color: 
      Attendees: 
      Kind: calendar#event
      Location: location2
      Organizer: me@testdomain.com
      Recurrence: RRULE:FREQ=WEEKLY;BYDAY=TH
      Start: 2014-07-31
      End: 2014-08-01
      Reminders: Not defailt, email:10,popup:10
    =====================
    Event ID: 1logvocs77jierahutgv962sus_20140814, ICalUID: 1logvocs77jierahutgv962sus@google.com
      Name: test event updated
      Description: test description2
      Status: confirmed
      Color: 
      Attendees: 
      Kind: calendar#event
      Location: location2
      Organizer: me@testdomain.com
      Recurrence: no recurrence
      Start: 2014-08-14
      End: 2014-08-15
      Reminders: Not defailt, email:10
    =====================
    Event ID: 974hqdhh8jhv5sdobkggmdvvd8, ICalUID: 974hqdhh8jhv5sdobkggmdvvd8@google.com
      Name: One hour event
      Description: test description
      Status: confirmed
      Color: 7
      Attendees: 
      Kind: calendar#event
      Location: Meeting Room Hire, Broadway, 255 The Bdwy, Broadway, NSW 2007, Australia
      Organizer: me@testdomain.com
      Recurrence: no recurrence
      Start: 1/08/2014 10:00:00 AM
      End: 1/08/2014 11:00:00 AM
      Reminders: Default
    =====================
    Event ID: jkits4dnpq6oflf99mfqf1kdo0, ICalUID: jkits4dnpq6oflf99mfqf1kdo0@google.com
      Name: Calendar event via API
      Description: Programmatically created
      Status: confirmed
      Color: 6
      Attendees: 
      Kind: calendar#event
      Location: 
      Organizer: me@testdomain.com
      Recurrence: no recurrence
      Start: 2/08/2014 12:30:50 PM
      End: 2/08/2014 1:30:50 PM
      Reminders: Not defailt, popup:60
    =====================
    

    First event is recurrent weekly whole day event series. Second is updated single event of the first (has the same UID). Third is single event for one hour. The last is created by code above.

    Hope this will help others to economy their time.

    0 讨论(0)
  • 2020-12-04 02:09

    i was having same problem it was working fine on remote server but on the local server i got to that error, long story short after hours of headache i found out problem was from my system clock,just go through these step

    1. Click on the clock in your system

    • This will bring up the calendar and time

    2. Click Change date and time settings...

    • The Date and Time dialog will appear

    3. Click on the Internet Time tab

    4. Click Change settings

    • The Internet Time Settings dialog will appear.

    then finally update your clock with one of the time servers

    0 讨论(0)
  • 2020-12-04 02:19

    I'm not really sure what is wrong with your code I think its part how you are loading the key file. It could also be the fact that you don't need to send User with ServiceAccountCredential since the service account is the User you are loging in to. I am not sure why you are sending someones Gmail email.

    using Google.Apis.Auth.OAuth2;
    using System.Security.Cryptography.X509Certificates;
    using Google.Apis.Calendar.v3;
    namespace GoogleAnalytics.Service.Account
    {
        class Program
        {
            static void Main(string[] args)
            {
                //Install-Package Google.Apis.Calendar.v3
                string serviceAccountEmail = "1046123799103-6v9cj8jbub068jgmss54m9gkuk4q2qu8@developer.gserviceaccount.com";
                var certificate = new X509Certificate2(@"C:\Users\HP_User\Documents\GitHub\Google-Analytics-dotnet-ServiceAccount\GoogleAnalytics.Service.Account\Diamto Test Everything Project-bc63fd995bd7.p12", "notasecret", X509KeyStorageFlags.Exportable);
    
                ServiceAccountCredential credential = new ServiceAccountCredential(
                       new ServiceAccountCredential.Initializer(serviceAccountEmail)
                       {
                           Scopes = new[] { CalendarService.Scope.Calendar }
                       }.FromCertificate(certificate));
    
                // Create the service.
                var service = new CalendarService(new CalendarService.Initializer()
                {
                    HttpClientInitializer = credential,
                    ApplicationName = "CalendarService API Sample",
                });
    
                // define the new Calendar
                Google.Apis.Calendar.v3.Data.Calendar calendar = new Google.Apis.Calendar.v3.Data.Calendar();
                calendar.Description = "New Calendar";
                calendar.Summary = "New Calendar Summary";
                // Insert the Calendar
                service.Calendars.Insert(calendar).Execute();
                // List The Calendar
                var calList = service.CalendarList.List().Execute().Items;
    
            }
        }
    }
    

    This code is tested it shows you how to create the initial calender for the service account. Without creating a calendar it would return 0 calendars, you need to remember to create one first.

    0 讨论(0)
提交回复
热议问题