Service account authentication can be done directly with .p12 files or with
JSON Key files.
Currently, the .NET library only supports .p12 files. This feature requests
is to add support for JSON key files
see
https://cloud.google.com/storage/docs/authentication#generating-a-private-key
Some additional references for JSON key files in java and go libraries:
https://code.google.com/p/google-api-java-client/source/browse/google-api-client
/src/main/java/com/google/api/client/googleapis/auth/oauth2/GoogleCredential.jav
a#776
https://github.com/golang/oauth2/issues/20
https://issues.jenkins-ci.org/browse/JENKINS-24571
cross reference with:
https://code.google.com/p/google-api-dotnet-client/issues/detail?id=280
Original issue reported on code.google.com by [email protected] on 23 Feb 2015 at 7:18
Actually, this has been added in 1.9.3 release a while ago.
Not sure if I'm missing something, but nowhere in the source code can I find any implementation of authorization for a Service Account using a JSON key file.
GoogleCredential.FromStream allows you to create service account credential from the JSON key.
https://github.com/google/google-api-dotnet-client/blob/master/Src/GoogleApis.Auth.DotNet4/OAuth2/GoogleCredential.cs#L87
At lower level, service account credential can be created from a PKCS-8 key, which is the private key format used in JSON keys:
https://github.com/google/google-api-dotnet-client/blob/master/Src/GoogleApis.Auth.DotNet4/OAuth2/ServiceAccountCredential.cs#L88
All the links referenced by @jtattermusch are dead and serve 404 errors. Is there any documentation on this?
@runxc1 The new link I believe is this:
https://github.com/google/google-api-dotnet-client/blob/master/Src/Support/GoogleApis.Auth.DotNet4/OAuth2/GoogleCredential.cs#L96
The full source code should be like this
GoogleCredential credential;
using (var stream = new FileStream(fileName, FileMode.Open, FileAccess.Read))
{
credential = GoogleCredential.FromStream(stream)
.CreateScoped(VisionService.Scope.CloudPlatform);
}
var service = new VisionService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "my-app-name",
});
How do you define a user to impersonate? For the Directory Service this is how I used to do it with a .p12 file:
var certificate = new X509Certificate2(HttpContext.Current.Server.MapPath(relativeKeypath), "notasecret", X509KeyStorageFlags.Exportable);
return new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(serviceAccountEmail)
{
User = user,
Scopes = scopes
}.FromCertificate(certificate));
If I don't specify a User I get an Invalid Credentials [401] error.
How do I do this now?
@samofwise You can create new service account for this.
Go to IAM & Admin Service accounts, click Create service account and use path to created json files as fileName in my prev sample.


@sergey-tihon Thanks for your help (very descirptive), However I think you misunderstood me (sorry if I wasn't very clear.
I have done the above process and generated my json file and I am using your code from above
But the service account I am wanting to use is one with Domain Wide Delegation (I have already set it up)
Along with this I need to impersonate a particular user (ie [email protected]).
When using a p12 key i did this by setting the User property on the ServiceAccountCredential.Initializer
User = [email protected]
However with the new GoogleCredential class there is no option to do this.
So how do i set a user to impersonate with the new GoogleCredential class?
I used this - http://stackoverflow.com/questions/38496919/googlecredential-created-by-json-private-key-file-serviceaccount-how-to-set
Odd that it wouldn't be supported directly by the API.
APIs and authentication are two separate things. Not all of the APIs for example support services accounts. The core library handles authentication and the classes for the specific api handles its own functionality and accept the authentication from the core library.
This may help as well http://www.daimto.com/google-service-accounts-with-json-file/
Was having the same problem. I could not find any easy way to read the credentials from a stream _and_ have the User set for the credential.
The API kept giving Bad Request 400, preconditionFailed.
I therefore solved it the dirty way - with reflection. It did solve my issue:
ServiceAccountCredential credential;
var scopes = ScopeConverter.Convert(context.Scopes);
using (var stream = new FileStream(context.ServerSecretFilePath, FileMode.Open, FileAccess.Read))
{
credential =
GoogleCredential
.FromStream(stream)
.CreateScoped(scopes)
.UnderlyingCredential as ServiceAccountCredential;
}
var userField = typeof(ServiceAccountCredential).GetField("user", BindingFlags.NonPublic | BindingFlags.Instance);
userField?.SetValue(credential, "[email protected]");
return credential;
@cldons I get an exception: Client is unauthorized to retrieve access tokens using this method.
Did you have to work around that? Or do I have something configured wrong?
Can we somehow make an official example on how to do this?
I guess that is more of an auth problem directly with the APIs and the user you are trying to use. Make sure that you configure correctly your auth settings, as described here (for instance):
https://stackoverflow.com/questions/42784640/client-is-unauthorized-to-retrieve-access-tokens-using-this-method-gmail-api-c-s
My solution was more focussed on how to achieve impersonation / setting a private field.
@eluchsinger Yes, this is more likely to be an problem with your auth configuration.
@cldons Just so you know, there is now a CreateWithUser() method to set the user on a service credential: https://github.com/google/google-api-dotnet-client/blob/master/Src/Support/Google.Apis.Auth/OAuth2/GoogleCredential.cs#L276
@eluchsinger which api are you trying to access? Not all APIs support service accounts.
Link to example json with service account @chrisdunelm if you have any improvements on that let me know
Most helpful comment
The full source code should be like this