Access Google Calendar API using Service Account Authentication

10,886

Solution 1

I am curious as to why your first attempt with the service account tutorial didn't work. What was wrong? Was there an error?

Remember service accounts are not you. The service account has its own Google calendar account, so if you are trying to read one of your "personal calendars", it will not work. You are going to have to share your personal calendar with the service account.

Here is another example using the Json service account key file.

string[] scopes = new string[] { CalendarService.Scope.Calendar };
GoogleCredential credential;
using (var stream = new FileStream(serviceAccountCredentialFilePath, FileMode.Open, FileAccess.Read))
{
    credential = GoogleCredential.FromStream(stream)
                     .CreateScoped(scopes);
}

// Create the Calendar service.
var service = new CalendarService(new BaseClientService.Initializer()
{
    HttpClientInitializer = credential,
    ApplicationName = "Calendar Authentication Sample",
});

Solution 2

Try this. First Create a service account which can be found in your Google Dev Console.

For reference on implementation, check DalmTo's blogpost on how to use Service Accounts here.

Here's a snippet:

var certificate = new X509Certificate2(keyFile, "notasecret", X509KeyStorageFlags.Exportable);
try{
   ServiceAccountCredential credential = new ServiceAccountCredential(
      new ServiceAccountCredential.Initializer(serviceAccountEmail)
      {
          Scopes = scopes
      }.FromCertificate(certificate));

   //Create the service.
   DriveService service = new DriveService(new BaseClientService.Initializer()
   {
      HttpClientInitializer = credential,
      ApplicationName = "Drive API Sample"
   });
   return service;
}
catch (Exception ex)
{
    Console.WriteLine(ex.InnerException);
    return null;
}

Solution 3

For anybody finding their way to this question but needing a NodeJS solution, this is how you can log in with a service account that has domain-wide delegation permissions as a specific user:

const auth = new google.auth.JWT({    // use JWT instead of GoogleAuth 
    subject: "[email protected]",      // specify subject (user whose context you want to operate in)
    keyFile: "service-account-key.json",
    scopes: [
        "https://www.googleapis.com/auth/calendar.events",
        "https://www.googleapis.com/auth/calendar.readonly"
    ],
})

Solution 4

visit this link have complete working project google service account authentication with google calendar event insert method you have to change your json private key and your Credentials only https://github.com/CodeForget/Google-Service-Account-Authentication

here json key file othentication as well p12 authentication both

ServiceAccountAuthentication.cs

using Google.Apis.Calendar.v3;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Services;
using System;
using System.IO;
using System.Security.Cryptography.X509Certificates;
using Google.Apis.Calendar.v3.Data;

namespace GoogleSamplecSharpSample.Calendarv3.Auth
{



    public static class ServiceAccountExample
    {

        /// <summary>
        /// Authenticating to Google calender using a Service account
        /// Documentation: https://developers.google.com/accounts/docs/OAuth2#serviceaccount
        /// </summary>
        /// Both param pass from webform1.aspx page on page load
        /// <param name="serviceAccountEmail">From Google Developer console https://console.developers.google.com/projectselector/iam-admin/serviceaccounts </param>
        /// <param name="serviceAccountCredentialFilePath">Location of the .p12 or Json Service account key file downloaded from Google Developer console https://console.developers.google.com/projectselector/iam-admin/serviceaccounts </param>
        /// <returns>AnalyticsService used to make requests against the Analytics API</returns>

        public static CalendarService AuthenticateServiceAccount(string serviceAccountEmail, string serviceAccountCredentialFilePath, string[] scopes)
        {
            try
            {
                if (string.IsNullOrEmpty(serviceAccountCredentialFilePath))
                    throw new Exception("Path to the service account credentials file is required.");
                if (!File.Exists(serviceAccountCredentialFilePath))
                    throw new Exception("The service account credentials file does not exist at: " + serviceAccountCredentialFilePath);
                if (string.IsNullOrEmpty(serviceAccountEmail))
                    throw new Exception("ServiceAccountEmail is required.");

                // For Json file
                if (Path.GetExtension(serviceAccountCredentialFilePath).ToLower() == ".json")
                {
                    GoogleCredential credential;
                    //using(FileStream stream = File.Open(serviceAccountCredentialFilePath, FileMode.Open, FileAccess.Read, FileShare.None))


                    using (var stream = new FileStream(serviceAccountCredentialFilePath, FileMode.Open, FileAccess.Read))
                    {
                        credential = GoogleCredential.FromStream(stream)
                             .CreateScoped(scopes).CreateWithUser("[email protected]");//put a email address from which you want to send calendar its like (calendar by xyz user )
                    }

                    // Create the  Calendar service.
                    return new CalendarService(new BaseClientService.Initializer()
                    {
                        HttpClientInitializer = credential,
                        ApplicationName = "Calendar_Appointment event Using Service Account Authentication",
                    });
                }
                else if (Path.GetExtension(serviceAccountCredentialFilePath).ToLower() == ".p12")
                {   // If its a P12 file

                    var certificate = new X509Certificate2(serviceAccountCredentialFilePath, "notasecret", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.Exportable);
                    var credential = new ServiceAccountCredential(new ServiceAccountCredential.Initializer(serviceAccountEmail)
                    {
                        Scopes = scopes
                    }.FromCertificate(certificate));

                    // Create the  Calendar service.
                    return new CalendarService(new BaseClientService.Initializer()
                    {
                        HttpClientInitializer = credential,
                        ApplicationName = "Calendar_Appointment event Using Service Account Authentication",

                    });
                }
                else
                {
                    throw new Exception("Something Wrong With Service accounts credentials.");
                }

            }
            catch (Exception ex)
            {                
                throw new Exception("Create_Service_Account_Calendar_Failed", ex);
            }
        }


    }
}

add webform.aspx and put this code on webform.aspx.cs

using System;
using Google.Apis.Calendar.v3;
using GoogleSamplecSharpSample.Calendarv3.Auth;
using Google.Apis.Calendar.v3.Data;

namespace CalendarServerToServerApi
{
    public partial class WebForm1 : System.Web.UI.Page
    {
        // create event which you want to set using service account authentication 
        Event myEvent = new Event
        {
            Summary = "Visa Counselling",
            Location = "Gurgaon sector 57",
            Start = new EventDateTime()
            {
                DateTime = new DateTime(2017, 10, 4, 2, 0, 0),
                TimeZone = "(GMT+05:30) India Standard Time"
            },
            End = new EventDateTime()
            {
                DateTime = new DateTime(2017, 10, 4, 2, 30, 0),
                TimeZone = "(GMT+05:30) India Standard Time"
            }
            //,
            // Recurrence = new String[] {
            //"RRULE:FREQ=WEEKLY;BYDAY=MO"
            //}
            //,
            // Attendees = new List<EventAttendee>()
            // {
            // new EventAttendee() { Email = "[email protected]" }
            //}
        };

        protected void Page_Load(object sender, EventArgs e)
        {

        }


        public void Authenticate(object o, EventArgs e)
        {
            string[] scopes = new string[] {
     CalendarService.Scope.Calendar //, // Manage your calendars
    //CalendarService.Scope.CalendarReadonly // View your Calendars
 };
            string cal_user = "[email protected]"; //your CalendarID On which you want to put events
            //you get your calender id "https://calendar.google.com/calendar"
            //go to setting >>calenders tab >> select calendar >>Under calender Detailes at Calendar Address:

            string filePath = Server.MapPath("~/Key/key.json");
            var service = ServiceAccountExample.AuthenticateServiceAccount("[email protected]", filePath, scopes);
            //"[email protected]" this is your service account email id replace with your service account emailID you got it .
            //when you create service account https://console.developers.google.com/projectselector/iam-admin/serviceaccounts

            insert(service, cal_user, myEvent);

        }



        public static Event insert(CalendarService service, string id, Event myEvent)
        {
            try
            {
                return service.Events.Insert(myEvent, id).Execute();

            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                return null;
            }
        }


    }
}
Share:
10,886

Related videos on Youtube

Tono Nam
Author by

Tono Nam

Updated on June 04, 2022

Comments

  • Tono Nam
    Tono Nam almost 2 years

    I was able to access the Google Calendar API using the .NET Quickstart tutorial and it worked great!

    The problem with that tutorial is that it uses Open Authentication or OAuth2. I will like to do the same using Service Account Authentication.

    (https://support.google.com/googleapi/answer/6158857?hl=en)

    Can someone give me an example of how I can access my calendar using a Service account key file?

    I have tried also tried using Google Calendar API Authentication with C# tutorial and was not able to accomplish it.

  • dybzon
    dybzon over 6 years
    This (and your blog post) was a great help for me. Finally made my app authenticate towards the Google Calendar API using a service account. Thanks!
  • Jalal El-Shaer
    Jalal El-Shaer over 5 years
    Hi. Any hints about how to " ... share your personal calendar with the service account.". I'm having hard time getting this together. Please advise
  • DaImTo
    DaImTo over 5 years
    Take the service accounts email address and share your calendar with it like you would share any other user. note the calendar id when you do. it will now have pre-approval
  • Jalal El-Shaer
    Jalal El-Shaer over 5 years
    Yes. I'm doing so. I went to my calendar, to "Add a friend's calendar" and entered the service email. Then I got this error: Cannot add calendar "[email protected]‌​.com" You do not have access to [email protected].‌​com's calendar
  • Jalal El-Shaer
    Jalal El-Shaer over 5 years
    Basically, I added a new project, enabled Calendar API, then added a 'service account' credential. I then configured it to have "Domain-Wide Delegation". I tried the .json and .p12 ways to interact with the api. No errors from the code, but nothing appears in My Calendar.
  • Jalal El-Shaer
    Jalal El-Shaer over 5 years
    Extra info that might help: I don't have a G Suite account, its just a regular gmail account. Can this still work ?
  • DaImTo
    DaImTo over 5 years
    you don't need a gsuite account you just need the email address of the service account from Google developers console
  • dcdrns
    dcdrns almost 4 years
    One important thing. Just sharing a calendar with the service account is not enough now. You have to accept it in the service account by CalendarList.insert(calendarId). Please refer to link
  • DaImTo
    DaImTo almost 4 years
    @dcdrns What makes you say that? Share the calendar with the service account or set up domain wide delegation with gsuite was always the case. YOur issue Calendarlist.list has nothing to do with this question.
  • Arash Motamedi
    Arash Motamedi about 3 years
    Do you know how to achieve that user context .CreateWithUser("[email protected]") in the plain HTTP auth or calendar API calls? (Or in the NodeJS library)
  • T. Webster
    T. Webster almost 3 years
    Sharing my personal calendar with the service account was exactly what I needed to do. Thank you @JalalEl-Shaer!