Authenticate to use Google Sheets with service account instead of personal account in C# .NET

5.1k views Asked by At

I have an application that I developed that utilizes a few Google Sheets.

I was able to figure out how to get it to have access to the Google Sheets API using the following code:

    UserCredential credential;
    using (var stream =
                  new FileStream("client_secret.json", FileMode.Open, FileAccess.Read))
    {
        string credPath = System.Environment.GetFolderPath(
            System.Environment.SpecialFolder.Personal);


        credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
            GoogleClientSecrets.Load(stream).Secrets,
            Scopes,
            "user",
            CancellationToken.None,
            new FileDataStore(credPath, true)).Result;
        Console.WriteLine("Credential file saved to: " + credPath);
    }
    // Create Google Sheets API service.
    var service = new SheetsService(new BaseClientService.Initializer()
    {
        HttpClientInitializer = credential,
        ApplicationName = ApplicationName,
    });

This application will be used by a few other people - but the first time they run the application it asks them to login to Google - but their accounts don't give them the appropriate access.

I think (correct me if I'm wrong) - using a Service Account should resolve my issue and no longer prompt a user to 'login', but still allow my application to read/update the Sheets appropriately.

I'd like to take my existing code and modify it to use a Service Account but I can't find any good documentation on how to do that. I have created the Service Account and have the ServiceAccount.json file in the same spot as the current 'client_secret.json' file but am unsure how to proceed much further.

I have tried changing the code to:

    ServiceAccountCredential credential;
    //UserCredential credential;
    using (var stream =
        new FileStream("HelperServiceAccount.json", FileMode.Open, FileAccess.Read))
    {
        string credPath = System.Environment.GetFolderPath(
            System.Environment.SpecialFolder.Personal);


        credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
            GoogleClientSecrets.Load(stream).Secrets,
            Scopes,
            "user",
            CancellationToken.None,
            new FileDataStore(credPath, true)).Result;
            )
        Console.WriteLine("Credential file saved to: " + credPath);
    }
    // Create Google Sheets API service.
    var service = new SheetsService(new BaseClientService.Initializer()
    {
        HttpClientInitializer = credential,
        ApplicationName = ApplicationName,
    });

But it fails - the credential variable gives an error.

Any ideas?

3

There are 3 answers

0
Vlad Rudenko On

Shortest code:

var credential = (ServiceAccountCredential)GoogleCredential
    .FromFile("client_secret.json")
    .CreateScoped(SheetsService.Scope.Spreadsheets)
    .UnderlyingCredential;

var service = new SheetsService(new BaseClientService.Initializer
{
    HttpClientInitializer = credential,
    ApplicationName = AppName,
});
1
Daniel_dev On

I've made this project to allow users to create service accounts credentials using both json or p12 credential files. And if you want to access user data from your domain, be sure to enable the wide domain delegation option before.

GoogleApiServiceFactory

1
D Joyce On

You should have created the service account and stored the json credential file:

Then try this:

        ServiceAccountCredential credential;
        string[] Scopes = { SheetsService.Scope.Spreadsheets };
        string serviceAccountEmail = "[email protected]";
        string jsonfile = "xxxxxxxx-xxxxxxx.json";
        using (Stream stream = new FileStream(@jsonfile, FileMode.Open, FileAccess.Read, FileShare.Read))
        {
            credential = (ServiceAccountCredential)
                GoogleCredential.FromStream(stream).UnderlyingCredential;

            var initializer = new ServiceAccountCredential.Initializer(credential.Id)
            {
                User = serviceAccountEmail,
                Key = credential.Key,
                Scopes = Scopes
            };
            credential = new ServiceAccountCredential(initializer);
        }