2

I have created an console application that uses OAuth2 to authenticate with the GoogleAnalyticsApiV4 to query some data. The application works as intended but we would like to automate the process so the application can be scheduled to run once a day. The problem here is the application would be hosted on azure and there is no way for a user to accept the authentication request with google that pops up in a browser the first time the application runs.

Following posts online and googles documentation my current solution to authenticate is this

     try
        {
            var credential = GetCredential().Result;

            using (var svc = new AnalyticsReportingService(
            new BaseClientService.Initializer
            {
                HttpClientInitializer = credential,
                ApplicationName = "Google Analytics API Console"
            }))
        {
           ///// Query some data/////
        } 



static async Task<UserCredential> GetCredential()
{
    using (var stream = new FileStream("client_secret.json",
         FileMode.Open, FileAccess.Read))
    {
        string loginEmailAddress = ConfigurationManager.AppSettings["GoogleUsername"];
        return await GoogleWebAuthorizationBroker.AuthorizeAsync(
            GoogleClientSecrets.Load(stream).Secrets,
            new[] { AnalyticsReportingService.Scope.Analytics },
            loginEmailAddress, CancellationToken.None,
            new FileDataStore("GoogleAnalyticsApiConsole"));
    }
}

This solution works perfectly well to authenticate with Google as long as a user is available to input credentials and accept the authentication request. Unfortunately as soon as the application is moved to another machine it needs to re-authenticate and a user needs to input credentials again and accept the request.

I have been searching for a way to take the User out of the process so the application can run on azure but have not found anything clear on how to do this in c#.

Please can someone either describe how i can authenticate my application with google without a user, or point me in the direction of documentation that accurately covers the process.

An help or examples would be greatly appreciated.

1 Answer 1

1

You have a couple of options.

Is this an account you have access to. If it is then you can use a service account. Service accounts are preauthorized the you take the service account email address and add it as a user in Google analytics admin at the account level and the service account will be able to access the account for as long as it is valid. No pop up window is required. I have some sample code on how to authenticate with a service account here

/// <summary>
    /// Authenticating to Google using a Service account
    /// Documentation: https://developers.google.com/accounts/docs/OAuth2#serviceaccount
    /// </summary>
    /// <param name="serviceAccountEmail">From Google Developer console https://console.developers.google.com</param>
    /// <param name="serviceAccountCredentialFilePath">Location of the .p12 or Json Service account key file downloaded from Google Developer console https://console.developers.google.com</param>
    /// <returns>AnalyticsService used to make requests against the Analytics API</returns>
    public static AnalyticsReportingService AuthenticateServiceAccount(string serviceAccountEmail, string serviceAccountCredentialFilePath)
    {
        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.");

            // These are the scopes of permissions you need. It is best to request only what you need and not all of them
            string[] scopes = new string[] { AnalyticsReportingService.Scope.Analytics };             // View your Google Analytics data

            // For Json file
            if (Path.GetExtension(serviceAccountCredentialFilePath).ToLower() == ".json")
            {
                GoogleCredential credential;
                using (var stream = new FileStream(serviceAccountCredentialFilePath, FileMode.Open, FileAccess.Read))
                {
                    credential = GoogleCredential.FromStream(stream)
                         .CreateScoped(scopes);
                }

                // Create the  Analytics service.
                return new AnalyticsReportingService(new BaseClientService.Initializer()
                {
                    HttpClientInitializer = credential,
                    ApplicationName = "AnalyticsReporting Service account Authentication Sample",
                });
            }
            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  AnalyticsReporting service.
                return new AnalyticsReportingService(new BaseClientService.Initializer()
                {
                    HttpClientInitializer = credential,
                    ApplicationName = "AnalyticsReporting Authentication Sample",
                });
            }
            else
            {
                throw new Exception("Unsupported Service accounts credentials.");
            }

        }
        catch (Exception ex)
        {
            Console.WriteLine("Create service account AnalyticsReportingService failed" + ex.Message);
            throw new Exception("CreateServiceAccountAnalyticsReportingFailed", ex);
        }
    }

If this isn't something you can do. Then you should be aware of the fact that filedatastore() by default stores your credentials in %appData% you could simply copy that file onto the new server along with the code.

You can also move the location to some were other then %appData% by using the following code:

new FileDataStore(@"c:\datastore",true)     

I have a tutorial on how filedatastore works. here File datastore demystified

Preauthorizing service account to Google Analytics. Admin section of the Google analytics website. Grant it read access should be more then enough.

enter image description here

Sign up to request clarification or add additional context in comments.

7 Comments

Thank you for the swift reply, I have access to the account so i am looking at your sample code now.
make sure when you give it access in google analytics admin you do it at the ACCOUNT level. if you have any issues with the sample let me know.
I'm having a slight issue setting my file path to the json file for the service account credentials. I changed the name of the file to Secret.json, Would this affect anything? I cant see why a string of "/Files/Secret.json" wouldn't work
It shouldn't. Azure can be a pain though as far as where it has access to what files.
Thank you so much for your help, your solution works perfectly and is very clear. I will make sure to tick your solution as soon as stack overflow allows me.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.