Using Google SpreadsheetsService with Service Account - c#

I need to make some changes to existing Spreadsheet in Google Drive. I want to do that periodically, using scheduled process. Due to this I decided to use service account authentication, which is described here https://developers.google.com/drive/web/delegation
The example is working fine and I can connect to the Plus API, however I need to connect to Google Spreadsheet API. The problem is that SpreadsheetsService does not seems to work with p12 files or Initializer class as DriveService does.
SpreadSheetsService has only 2 authentication methods which seems not to require to go by provided url - SetAuthenticationToken() and setUserCredentials(). There is no obvious way I can pass p12 file to the SpreadsheetService.
Did anyone solved this problem? I am okay with any "dirty" solution like decrypting p12 file (thought I don't think google provides password for this) or putting authentication headers from DriveService to SpreadsheetService. Did anyone solved this problem?
Or maybe there are 3rd parties libraries for C# that supports Spreadsheet API login via Service account?
Thanks.

Please refer to How to use SpreadsheetsService authenticated by ServiceAccountCredential?
ServiceAccountCredential credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(ServiceAccount) {
Scopes = new[] {DriveService.Scope.Drive,"https://spreadsheets.google.com/feeds"}
}.FromCertificate(certificate)
);
bool success = credential.RequestAccessTokenAsync(System.Threading.CancellationToken.None).Result;
....
SpreadsheetsService spreadsheetsService = new SpreadsheetsService(applicationName);
var requestFactory = new Google.GData.Client.GDataRequestFactory(applicationName);
requestFactory.CustomHeaders.Add(string.Format("Authorization: Bearer {0}", credential.Token.AccessToken));
spreadsheetsService.RequestFactory = requestFactory;

Related

Mailkit Office365 AcquireTokenInteractive requires client_secret

So this is an issue that has been plaguing me for a bit and my deadline is coming up. I'm working on an application that sends emails and my workplace uses Office365 via Exchange. I'm using a C# webapp and using Mailkit to deliver emails.
The issue (not really an issue but good practice that's getting in my way) is that we made an email account to deliver mail yet our organization requires MFA. After talking about it with my director, creating an app password would not be a good idea for how this program is deployed so I'm trying to find ways to authenticate properly.
I eventually landed on using the Microsoft.Identity.Client library to require logging in via a registered Azure application. I could then cache this and refresh as needed, this way making sure the access is still valid.
However, I'm stuck on something. I have the app registration set to public with no client secrets or certificates with all of the necessary permissions. However right at the var oauth2 step, it fails while giving the error "Original exception: AADSTS7000218: The request body must contain the following parameter: 'client_assertion' or 'client_secret'."
The issue is that the application is public and is defined to allow public client flows. So I'm not getting how the request could still require a client secret when that's not how I'm building the request at all. I tried using private, but because of the MFA requirement, that fails too.
Below is what I have. Ignore that I'm hard coding stuff; it's temporary until I can get this sorted out. I'm also only scoping the SMTP permissions because all this application needs to do is send an email; IMAP isn't needed since it's not reading or anything else.
var options = new PublicClientApplicationOptions
{
ClientId = "[clientID]",
TenantId = "[tenandID]",
RedirectUri = "http://localhost"
};
var publicClientApplication = PublicClientApplicationBuilder
.CreateWithApplicationOptions(options)
.Build();
var scopes = new string[] {
"email",
"offline_access",
"https://outlook.office.com/SMTP.Send" // Only needed for SMTP
};
var authToken = await publicClientApplication.AcquireTokenInteractive(scopes).ExecuteAsync();
//Here is where it returns that it needs a client_secret and won't advance.
// The login window appears and states it was successfully authenticated,
// but the application crashes with that error at this step.
var oauth2 = new SaslMechanismOAuth2(Config.Env.smtpUser, authToken.AccessToken);

Google api OAuth fails with redirect uri mismatch

I have a website, where I can create Events for members, and I am trying to connect to google calendar API, so when ever i create a new event, i can then sync that to the calendar.
I have followed this guide: https://developers.google.com/calendar/quickstart/dotnet
But when i get to the part where i run the sample code, and have to authenticate by OAuth.
I get the following:
My Code:
public class InitializeGoogleCalendarApiHelper : IInjected
{
public InitializeGoogleCalendarApiHelper(ILogger logger)
{
this.logger = logger;
}
// If modifying these scopes, delete your previously saved credentials
// at ~/.credentials/calendar-dotnet-quickstart.json
static string[] Scopes = { CalendarService.Scope.CalendarReadonly };
static string ApplicationName = "Nordmanni Google Calendar API";
private readonly ILogger logger;
public CalendarService Initialize()
{
UserCredential credential;
using (var stream =
new FileStream("C:/Projects/Nordmanni/Nordmanni.App/credentials.json", FileMode.Open, FileAccess.Read))
{
// The file token.json stores the user's access and refresh tokens, and is created
// automatically when the authorization flow completes for the first time.
string credPath = "C:/Projects/Nordmanni/Nordmanni.App/GoogleApiToken.json";
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
Scopes,
"user",
CancellationToken.None,
new FileDataStore(credPath, true)).Result;
logger.Info<InitializeGoogleCalendarApiHelper>($"Credential file saved to: {credPath}");
}
// Create Google Calendar API service.
var service = new CalendarService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = ApplicationName,
});
return service;
}
}
I am running the website locally for now, in visual studio.
The port number changes for each request i have made, so setting the port number does not seem to work.
These are the settings i setup in google.
I have spent the last day and a half, looking for a solution, but have been unable to find anything so far.
I have downloaded the credentials.json and added to the solution.
Any resources or links are welcome, or sample code which i could look at.
I am unsure if i have setup the domains correctly , or if it is even possible to setup while running it locally.
We had a similar problem a while ago, as far as I am assuming you are trying to authorise from your backend service for google API
Solution we employed
We used google service account for that. It is simple and elegant to use
Step - 1: Setup google service account
Follow this link to setup a service account using google developer console
https://developers.google.com/android/management/service-account
Step - 2: Share your google Application with service account email-id
This step gives your service account access to the google application may it be calendar or google docs or google sheets
Similar to sharing document with other users
https://support.google.com/calendar/answer/37082?hl=en (This link shows how to share your calendar with other emailId)
Step - 3: Follow these links to integrate service account with your application
https://developers.google.com/identity/protocols/oauth2/service-account
https://cloud.google.com/docs/authentication/production
Advantage of google service account is that you don't have to login at regular intervals to update the data. Set it up once and you can forget about it
Hope my answer helps :)

Access Api created google spreadsheet on Browser

I trying to create a spreadsheet using the google spreadsheets v4. I generated a new server to server credential json on console api. All appears to work, but when I try to access the generated url, I got a screen saying to request permission. The credential was generated from my own service account, associated with my own google account, so I understand that I already have this permission. What could I do to access the generated sheet on browser? Above my code to generate the spreadsheet and the screen I getting.
public class Program
{
static string[] Scopes = { SheetsService.Scope.Spreadsheets, SheetsService.Scope.Drive, SheetsService.Scope.DriveFile };
static string ApplicationName = "Google Sheets API .NET Quickstart";
public static void Main(string[] args)
{
AppendData();
}
public static void AppendData()
{
// the downloaded jsonn file with private key
var credential = GoogleCredential.FromStream(new FileStream(Environment.CurrentDirectory + "/ApiKey/api_key.json", FileMode.Open)).CreateScoped(Scopes);
var service = new SheetsService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = ApplicationName,
});
Spreadsheet requestBody = new Spreadsheet()
{
Properties = new SpreadsheetProperties()
{
Title = "Calculo Projeção",
},
};
SpreadsheetsResource.CreateRequest request = service.Spreadsheets.Create(requestBody);
}
}
So, the GSheet you've created was created using the service account. This means that the service account is the owner of the GSheet.
Depending on what your end goal is, and what type of Google Account you're using you may have some options here.
If you're using a G Suite account, the solution is relatively simple. It's to use impersonation with the service account. You're then basically using the service account to impersonate a user to perform the actions. If you impersonate your own account while creating the GSheet, the owner will be your own account. The documentation talks about the specifics here.
If you're NOT using a G Suite account, but a 'normal' Google account, it becomes a bit more tricky. I can think of some options here though:
Quick and dirty: Create the GSheet with your personal account first and give the service account access to it.
Have the service account create the GSheet and use the API/library to give your personal account access.
Create the GSheet not with the service account, but using OAuth and your own credentials. There's several ways to go about this. A good starting point for this would be here...
I may have missed one or two here, but you should understand what's actually happening now.
NOTE: One very important thing you have to take into account. If you delete the service account, any and all Google Drive items (including Sheets, Docs, Forms, etc) get deleted without any way of getting them back.

google service account authentication with json file in .net 4.0

Need to authenticate google service account with OAuth.
I have google credentials file in json format.
refereed Google Service Account Authentication with Json file
able to create RASParameters but didn't know how to proceed further.
I am very new to google apis implementation.
found various examples of .p12 file but didn't find one with .json file.
And i am using .net 4.0 framework so can't use the googlecredential class which is available from .net 4.5+ framework.
I think that what you need to create is a JsonCredentialParameters with that Json file you have. This class is under the Google.Apis.Auth.OAuth2 namespace, so you just need to have the proper Google Apis Auth package to do this.
Then you can create a new ServiceAccountCredential with the proper user account and scopes.
protected override ServiceAccountCredential GetCredential()
{
var credentialParameters = GetCredentialParameters();
return new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(credentialParameters.ClientEmail)
{
Scopes = Scopes,
User = User
}.FromPrivateKey(credentialParameters.PrivateKey));
}
JsonCredentialParameters GetCredentialParameters()
{
return JsonSerializer.Deserialize<JsonCredentialParameters>(new FileStream(File, FileMode.Open));
}

Authorized failed when run Google.Apis.YouTube.Samples.Upload project from Github

I am new from youtube api. I would like to have a console program schedule upload videos to youtube without authorization everytime.
I see many posts and videos but not the complete story, I download the sample from Github and try to run it. It failed.
i follow the guide that
。create OAuth client ID and application type choose Other
。download code from github
。click allow in browser, lets youtube api manage youtube account.
img1 - client secret download from console developer and code from github
img2 - error message told me unauthorized
which part is wrong, how can i fix it? Please help!
The error your getting means that you have not authenticated the YouTubeService there must be something wrong with your credentials which i cant see because you haven't posted all your code.
The YouTube API does not support service accounts. You will need to authenticate your code at least once. This is done via a web browser and the client library you are using will store the credentials for "user" in %appData% directory.
The tutorial you are following doesn't say anything about not needing authentication. This is the code for the auth.
UserCredential credential;
using (var stream = new FileStream("client_secrets.json", FileMode.Open, FileAccess.Read))
{
credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
// This OAuth 2.0 access scope allows for full read/write access to the
// authenticated user's account.
new[] { YouTubeService.Scope.Youtube },
"user",
CancellationToken.None,
new FileDataStore(this.GetType().ToString())
);
}

Categories