Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to login to Google API with Service Account in C# - Invalid Credentials

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?

like image 593
Vic Lindsey Avatar asked Jul 14 '16 23:07

Vic Lindsey


People also ask

Can I login to GCP console using service account?

You cannot log in to the Google Cloud Console (GUI) using a service account.


1 Answers

It appears that the GoogleAnalytics cannot consume a generic GoogleCredential and interpret it as a ServiceAccountCredential (even though it is acknowledged, interally, that it is actually of that type). Thus you have to create a ServiceAccountCredential the hard way. It’s also unfortunate that GoogleCredential 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:

using System; using System.Diagnostics; using System.IO; using System.Reflection; using System.Text; using Google.Apis.Auth.OAuth2; using Google.Apis.Services; using Google.Apis.Analytics.v3; using Newtonsoft.Json;     .     .     . try {     // Get active credential     string credPath = _exePath + @"\Private-67917519b23f.json";      var json = File.ReadAllText(credPath);     var cr = JsonConvert.DeserializeObject<PersonalServiceAccountCred>(json); // "personal" service account credential      // Create an explicit ServiceAccountCredential credential     var xCred = new ServiceAccountCredential(new ServiceAccountCredential.Initializer(cr.ClientEmail)     {         Scopes = new[] {             AnalyticsService.Scope.AnalyticsManageUsersReadonly,             AnalyticsService.Scope.AnalyticsReadonly         }     }.FromPrivateKey(cr.PrivateKey));      // Create the service     AnalyticsService service = new AnalyticsService(         new BaseClientService.Initializer()         {             HttpClientInitializer = xCred,         }     );      // some calls to Google API     var act1 = service.Management.Accounts.List().Execute();      var actSum = service.Management.AccountSummaries.List().Execute();      var resp1 = service.Management.Profiles.List(actSum.Items[0].Id, actSum.Items[0].WebProperties[0].Id).Execute(); 

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:

{   "type": "service_account",   "project_id": "atomic-acrobat-135",   "private_key_id": "508d097b0bff9e90b8d545f984888b0ef31",   "private_key": "-----BEGIN PRIVATE KEY-----\nMIIE...o/0=\n-----END PRIVATE KEY-----\n",   "client_email": "[email protected]",   "client_id": "1123573016559832",   "auth_uri": "https://accounts.google.com/o/oauth2/auth",   "token_uri": "https://accounts.google.com/o/oauth2/token",   "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",   "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/google-analytics%40atomic-acrobat-135923.iam.gserviceaccount.com" } 
like image 136
Vic Lindsey Avatar answered Oct 14 '22 07:10

Vic Lindsey