I'm beating myself bloody trying to get a simple service acccount login to work in C#, to Google API and Google Analytics. My company is already getting data into Analytics, and I can query information with their Query Explorer, but getting started in .Net is not going anywhere. I am using a Google-generated json file with PKI, as the documentation says that such a service account is the proper way for computer-to-computer communication with Googla API. Code snipet:
public static GoogleCredential _cred;
public static string _exePath;
static void Main(string[] args) {
_exePath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetName().CodeBase).Replace(@"file:\", "");
var t = Task.Run(() => Run());
t.Wait();
}
private static async Task Run() {
try {
// Get active credential
using (var stream = new FileStream(_exePath + "\\Default-GASvcAcct-508d097b0bff.json", FileMode.Open, FileAccess.Read)) {
_cred = GoogleCredential.FromStream(stream);
}
if (_cred.IsCreateScopedRequired) {
_cred.CreateScoped(new string[] { AnalyticsService.Scope.Analytics });
}
// Create the service
AnalyticsService service = new AnalyticsService(
new BaseClientService.Initializer() {
HttpClientInitializer = _cred,
});
var act1 = service.Management.Accounts.List().Execute(); // blows-up here
It all compiles fine, but when it hit the Execute() statement, a GoogleApiException
error is thrown:
[Invalid Credentials] Location[Authorization - header] Reason[authError] Domain[global]
What am I missing?
In 2020 you don't need to do all this and the GoogleCredential works fine. The code in the question looks correct except for one line:
The
CreateScoped
method returns a copy of the credentials. If you reassign it back to itself it just works.For the sake of completeness, this is my test code that works perfectly:
The invalid credentials error is happening because the scopes you specified aren't actually getting sent with your credentials. I made the same mistake and only realized after I debugged and still saw 0 scopes on the credential after the
CreateScoped
call.A
GoogleCredential
is immutable soCreateScoped
creates a new instance with the specified scopes set.Reassign your credentials variable with the scoped result like so and it should work:
The accepted answer works because it's achieving the same thing in a more difficult way.
It appears that the GoogleAnalytics cannot consume a generic
GoogleCredential
and interpret it as aServiceAccountCredential
(even though it is acknowledged, interally, that it is actually of that type). Thus you have to create aServiceAccountCredential
the hard way. It’s also unfortunate thatGoogleCredential
does not expose the various properties of the credential, so I had to build my own.I used the JSON C# Class Generator at http://jsonclassgenerator.codeplex.com/ to build a "personal" ServiceAccountCredential object using the JSON library that is an automatic part of Google API (Newtonsoft.Json), retrieved essential parts of the downloaded json file of the service account, to construct the required credential, using its email and private key properties. Passing a genuine
ServiceAccountCredential
to the GoogleAnalytics service constructor, results in a successful login, and access to that account’s allowed resources.Sample of working code below:
Some may wonder what a Google-generated service account credential with PKI (Private Key) looks like. From the Google APIs Manager (IAM & Admin) at https://console.developers.google.com/iam-admin/projects, select the appropriate project (you have at least one of these). Now select Service accounts (from the left nav links), and CREATE SERVICE ACCOUNT at top of screen. Fill in a name, set the Furnish a new private key checkbox, then click Create. Google will cause an automatic download of a JSON file, that looks something like this:
Another option is to use
GoogleCredential.GetApplicationDefault()
. I believe this is the currently (Oct. 2018) recommended approach. Here's some F#, but it's more or less the same in C# modulo syntax:Now, just make sure that you set the
GOOGLE_APPLICATION_CREDENTIALS
to point to the file with the credentials JSON file, eg.GOOGLE_APPLICATION_CREDENTIALS=creds.json dotnet run
.