Reputation: 707
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
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