Marco
Marco

Reputation: 707

Google analytics reporting authorize service account

I'm trying to use google analytics API to report users information in a c# webapp using a service account.

I've downloaded the JWT file and linked it in the project. I have a problem hwe I try to authenticate the service account: when I call RequestAccessTokenAsync(cancellationToken) anc exception is thrown sayng that the Scope must not be an empty value, I'm not able to set the Scope beacuse I'm creating serviceAccountCredential from the json stream.

An alternative would be request an access token with serviceAccountCredential.GetAccessTokenForRequestAsync(serviceAccountCredential.TokenServerUrl) but in that case I've not understood how to supply that token to the report request, without that token the API call won't be authorized and will fail.

This is source code:

string viewId = "VIEW_ID";      
FileStream jwtSecretStream = new FileStream(@"path\to\servicesecret.json", FileMode.Open, FileAccess.Read);
var metrics = new List<Metric> { new Metric { Expression = "ga:users" } };
var dimensions = new List<Dimension> { new Dimension { Name = "ga:userType" } };
DateRange dateRange = new DateRange
{
     StartDate = DateTime.UtcNow.AddDays(-7).ToString("yyyy-MM-dd"),
     EndDate = DateTime.UtcNow.ToString("yyyy-MM-dd")
};
try
{
     serviceAccountCredential = ServiceAccountCredential.FromServiceAccountData(jwtSecretStream);
     // this call will throw the exception
     var x = await serviceAccountCredential.RequestAccessTokenAsync(CancellationToken.None); 
    //this call will return a valid token -> DON'T KNOW HOW TO PASS To THE REQUEST
    //var y = await serviceAccountCredential.GetAccessTokenForRequestAsync(serviceAccountCredential.TokenServerUrl); 
}
catch (Exception e)
{
    throw;
}
_analyticsReportingService = new AnalyticsReportingService(new AnalyticsReportingService.Initializer()
{
    HttpClientInitializer = serviceAccountCredential,
    //HttpClientInitializer = credential,
    ApplicationName = "TestAnalytics",
});
//If I execute the request I got UNAUTHORIZED because there's not a valid access token  
var response = _analyticsReportingService.Reports.BatchGet(getReportRequest).Execute();

How can I provide the service account with a valid scope or, in alternative, request an access token and put it in the batch reqeust?

Upvotes: 1

Views: 1225

Answers (1)

Linda Lawton - DaImTo
Linda Lawton - DaImTo

Reputation: 116868

This is the code i normally use to authenticate the service. Serviceaccount.cs

/// <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, 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 (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)
        {                
            throw new Exception("CreateServiceAccountAnalyticsreportingFailed", ex);
        }
    }
}

Service account bonus info

Service accounts are dummy users. They by default have their own google drive account google calendar and probably a few more. What they dont have by default is a Google Analytics account.

"The user don't have a google analytics account 403 forbidden".

This message comes when a user tries to access the Google analytics api and does not actually have access to any google analytics accounts.

You need to login to the web version of google analytics go to the admin section of the website you want the service account to access. Add the service account email address as a user at the Account level.

Upvotes: 2

Related Questions