question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Provide a way to add scopes to ServiceAccountCredential

See original GitHub issue

After multiple attempts, I finally was able to connect to a g-suite account.

Many tutorials online suggested using below code:

private const string FileName = "service_account.json";
private const string User = "user@example.com";
private const string ApplicationName = "My Test App";
private static readonly string[] Scopes = { GmailService.ScopeConstants.MailGoogleCom, GmailService.Scope.GmailSettingsBasic }


using (var stream = new FileStream(FileName, FileMode.Open, FileAccess.Read))
{
    credentials = ServiceAccountCredential.FromServiceAccountData(stream);
}

but when trying to access my mailbox I got errors all the time. Finally I initialized ServiceAccountCredentials like this:

credentials = GoogleCredential.FromFile(FileName)
                     .CreateScoped(Scopes)
                     .CreateWithUser(User)
                     .UnderlyingCredential as ServiceAccountCredential;

But this doesn’t feel right. Ideally, I’d like to be able to load service account credentials from a file, assign scopes, and user (if needed), but there is no API to do that on ServiceAccountCredential.

This would be the ideal way:

using (var stream = new FileStream(FileName, FileMode.Open, FileAccess.Read))
{
    credentials = ServiceAccountCredential
                         .FromServiceAccountData(stream)
                         .WithScopes(Scopes)
                         .WithUser(User);
}

If there is a better way please let me know.

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:7 (2 by maintainers)

github_iconTop GitHub Comments

1reaction
amanda-tarafacommented, Aug 21, 2020

As @jskeet suggested, for something like you are describing in your last comment, you should confirm with the Gmail API team. I strongly suspect you’ll need impersonation though and thus a different credential per call. You won’t need to have multiple GmailServices though, you can do something as follows:

// No credentials in the service client. You can keep just one service client.
GmailService gmailService = new GmailService(new BaseClientService.Initializer
{
    ApplicationName = ApplicationName
});

// Scoped credential, no impersonation. You can keep this cached.
GoogleCredential baseCredential = GoogleCredential.FromFile(FileName).CreateScoped(Scopes);

// Impersonated credentials. You can keep these cached or create them on the fly.
GoogleCredential userA = baseCredential.CreateWithUser("a@example.com");
GoogleCredential userB = baseCredential.CreateWithUser("b@example.com");

// Create and execute a request with a per-call credential for eahc user
var result1 = gmailService.Users.Settings.UpdateVacation(settings, "me").AddCredential(userA).Execute();
var result2 = gmailService.Users.Settings.UpdateVacation(settings, "me").AddCredential(userB).Execute();

I believe that batching should work as well, although I haven’t tried it. But as far as I know, batching will use the credential set on each individual requests, if any, over one set at the batch request level. So, something like this should work:

// Create a request with a per-call credential for eahc user
var req1 = gmailService.Users.Settings.UpdateVacation(settings, "me").AddCredential(userA);
var req2 = gmailService.Users.Settings.UpdateVacation(settings, "me").AddCredential(userB);

var batch = new BatchRequest(gmailService);

// Add the requests to the batch
batch.Queue(req1, callback);
batch.Queue(req2, callback);

await batch.ExecuteAsync();
1reaction
jskeetcommented, Aug 21, 2020

Okay, that sounds like a different question at that point - and one which would be better asked of the GMail team. It’s possible that there’s some permission you can give to the service account in order to access multiple user accounts without impersonation, but I don’t know.

What you could do is keep the result of GoogleCredential.FromFile(FileName).CreateScoped(Scopes) cached somewhere, so you just need to call CreateWithUser each time you need to access a different user. I believe that you’d still need a separate GmailService object each time though. @amanda-tarafa is that right, or does your recent work allow the credentials to be effectively overridden on a per-request basis?

Read more comments on GitHub >

github_iconTop Results From Across the Web

how should I set "scopes" when creating ...
I need to set the credentials scope to access some APIs my code is like that ServiceAccountCredential saCredential; using (var fs = new ......
Read more >
Class ServiceAccountCredential | Google API support ...
UseJwtAccessWithScopes. Gets the flag indicating whether Self-Signed JWT should be used when OAuth scopes are set. This flag will be ignored if this...
Read more >
Class ServiceAccountCredential (1.60.0) | .NET client library
The signed JWT will contain a "scope" claim with the scopes in Scopes if there are any, otherwise it will contain an "aud"...
Read more >
Create credentials with scopes | BigQuery
Create credentials with Drive and BigQuery API scopes. ... ServiceAccountCredentials.getApplicationDefault() .createScoped( ImmutableSet.of(
Read more >
Class GoogleCredential | Google API support libraries
ServiceAccountCredential does not have scopes built-in by default. Caller should invoke CreateScoped(IEnumerable<String>) to add scopes to the credential.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found