I'm having couple of issues with adding attendees to my calendar using google calendar API and service account.
My service account has domain-wide delegation ticket in the cloud console and I am able to create/update a event without adding attendees.
When I try to send request with attendee then I get following response:
Google.Apis.Requests.RequestError
Service accounts cannot invite attendees without Domain-Wide Delegation of Authority. [403]
Errors [Message[Service accounts cannot invite attendees without Domain-Wide Delegation of Authority.] Location[ - ] Reason[forbiddenForServiceAccounts] Domain[calendar]
This is how my code looks like:
var eventDetails = _calendarService.GetEvent(eventDto.EventId).GetAwaiter().GetResult();
eventDetails.Attendees.Add( new EventAttendee
{
DisplayName = "Test Name",
Email = "testemail#example.com" // I tried with few emails but results is same
});
_credential = AuthorizeServiceAccount();
_calendarService = new CalendarService(new BaseClientService.Initializer()
{
HttpClientInitializer = _credential,
ApplicationName = _calendarOptions.AplicationName,
});
var request = _calendarService.Events.Patch(eventRequest,_calendarOptions.CalendarId, eventId);
var result = await request.ExecuteAsync();
public GoogleCredential AuthorizeServiceAccount()
{
var serviceAccountCredential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(_calendarOptions.Id) // I'm using service account email here, tried with clientId but same result
{
ProjectId = _calendarOptions.ProjectId,
KeyId = _calendarOptions.KeyId,
User = _calendarOptions.User, // I tried with email from request or null value - for both same result
Scopes = _calendarOptions.Scopes, // ["https://www.googleapis.com/auth/gmail.send", "https://www.googleapis.com/auth/calendar.readonly","https://www.googleapis.com/auth/calendar.events","https://www.googleapis.com/auth/calendar" ],
}
.FromPrivateKey(_calendarOptions.Key));
return GoogleCredential.FromServiceAccountCredential(serviceAccountCredential);
}
Can you please help me so I will be able to add attendees to my events? I don't need to send emails to attendees but emails are required in google API. I don't want also to have G Suite domain account as it's paid.
Related
I have created a VisualStudio (C#) project, wihch use google classroom apis.
With Super admin, It can create a course, but with delegated admin, It returns an error.
I have use a delegated admin. Why does that error return ?
Errors [
Message[#UserCannotCreateCourse Current user cannot create courses.] Location[ - ] Reason[forbidden] Domain[global]
]
my code is below given
string[] Scopes = {ClassroomService.Scope.ClassroomCourses};
UserCredential credential;
using (var stream = new FileStream("credentials.json", FileMode.Open, FileAccess.Read))
{
string credPath = "token.json";
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
Scopes,
"user",
CancellationToken.None,
new FileDataStore(credPath, true)).Result;
Console.WriteLine("Credential file saved to: " + credPath);
}
var service = new ClassroomService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "Classroom test"
});
var body = new Course()
{
Name = "MyFirstClass",
OwnerId = "me"
};
var course = service.Courses.Create(body).Execute();
"credentials.json"File is from My Google Cloud Platform project.
My project is verificated.
./auth/classroom/courses
./auth/classroom/rosters
(etc.)
Delegated admin is created by Google Console.
I added custom admin role.
I found that the owner of the classroom course must a member of classroom_teachers Group. (If the account is not the super admin)
With an account that has not be a teacher, classroom api gets error.
And after becoming a teacher (manually sign-in, and create a classroom course), classroom api succeeded.
So, before creating a course, I join that account into classroom_teacher group.
Thank you.
I am trying to authenticate in order to use Outlook REST API to subscription to Outlook emails via Push Subscription. I am using this documentation for reference: https://learn.microsoft.com/en-us/previous-versions/office/office-365-api/api/version-2.0/notify-rest-operations
I created an app in portal.azure.com and provided Required permission on "Read user mail" under "Office 365 Exchange Online" api.
Grant Required permission of Read user mail Screenshot
I am using the following code to get a Bearer token using "Microsoft.Identity.Client" nuget package. But I am still not able to subscribe to the Outlook Push Notification REST API and I am getting 401 Unauthorized error.
static async Task<AuthenticationResult> AuthorizeAsync(string clientId)
{
var authority = $"https://login.microsoftonline.com/{tenantName}.onmicrosoft.com";
var app = new PublicClientApplication(clientId, authority);
string[] scopes = new string[] { "Mail.Read" };
var accounts = await app.GetAccountsAsync();
AuthenticationResult authenticationResult = null;
if (accounts.Any())
{
authenticationResult = await app.AcquireTokenSilentAsync(scopes, accounts.FirstOrDefault());
}
else
{
try
{
var username = $"{Environment.UserName}#microsoft.com";
authenticationResult = await app.AcquireTokenByIntegratedWindowsAuthAsync(scopes, username);
}
Has anyone worked on a similar issue to authenticate and create a Push notification Subscription to get Outlook emails and can please help?
I'm getting below error when I try to accessing YouTube Reporting Services API using Service Account.
Google.GoogleApiException HResult=0x80131500
Message=Google.Apis.Requests.RequestError The caller does not have
permission [403] Errors [ Message[The caller does not have
permission] Location[ - ] Reason[forbidden] Domain[global] ]
When I searched online, somewhere I saw we need to have GSuite subscription in order to use service account with API, is it correct?
Here is my code snippet:
String serviceAccountEmail = "xxxxxxxxxxxxx#youtubereportingapi.iam.gserviceaccount.com";
var certificate = new X509Certificate2(#"xxxxxxxx.p12", "notasecret", X509KeyStorageFlags.Exportable);
ServiceAccountCredential credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(serviceAccountEmail)
{
Scopes = new[] { YouTubeReportingService.Scope.YtAnalyticsReadonly, YouTubeReportingService.Scope.YtAnalyticsMonetaryReadonly }
}.FromCertificate(certificate));
var youtubeReportingService = new YouTubeReportingService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = Assembly.GetExecutingAssembly().GetName().Name
});
var jobsListResponse = youtubeReportingService.Jobs.List().Execute(); // Here its throwing error
In order to use a service account you must share data with it. I have never heard of using GSuite with a YouTube account you can have the admin try and set up domain wide delegation to the service account. However to my knowledge there is no way to share YouTube data with a service account.
Service accounts are not supported by the YouTube APIs. You will need to use Oauth2 and save your refresh token for access later. The docs only mention OAuth2.
I have a .Net Core MVC Web application that authenticates the user using AzureAD. At some stage I need to send an e-mail on behalf of that user.
I searched for some options and apparently I can do that using Microsoft Exchange Service or Office365 but for both options I need to get the user's credential.
An example using Office365 is below however I do not know how to user the signed in info to pass to the SMTP server.
My (partial) HomeController:
private readonly ClaimsPrincipal _principal;
public HomeController(IPrincipal principal){
_principal = principal as ClaimsPrincipal;
}
I can use _principal.FindFirst(ClaimTypes.Upn).Value to get the user's e-mail address but how do I get the password?
Am I in the right path or am I missing anything?
public static void SendEmail(string toAddress, string fromAddress, string subject, string content)
{
SmtpClient client = new SmtpClient();
client.Credentials = new NetworkCredential("", "");
client.Port = 587;
client.Host = "smtp.office365.com";
client.EnableSsl = true;
MailMessage newMail = new MailMessage();
newMail.To.Add(toAddress);
newMail.From = new MailAddress(fromAddress);
newMail.Subject = subject;
newMail.IsBodyHtml = true;
newMail.Body = "<html><body>" + content + "</body></html>";
client.Send(newMail);
}
I'm sorry if this is a broad question but I really need some light on how to achieve this. I'm happy to provide more details if necessary.
At some stage I need to send an e-mail on behalf of that user.
Per my understanding, you could use the cloud-based email service SendGrid to handle email delivery on behalf of your authenticated user's email address. The code for sending the email to test02#example.com for the user test01#example.com would look like this:
var client = new SendGridClient("<SendGrid-ApiKey>");
var msg = new SendGridMessage()
{
From = new EmailAddress("test01#example.com", "test01"),
Subject = "Hello World from the SendGrid CSharp SDK!",
PlainTextContent = "Hello, Email!",
HtmlContent = "<strong>Hello, Email!</strong>"
};
msg.AddTo(new EmailAddress("test02#example.com", "Test02"));
var response = await client.SendEmailAsync(msg);
Detailed tutorial, you could follow sendgrid-csharp.
I want to start developing with Google API’s with a .NET client. For first step I tried to get all google contacts and now I want to insert contacts.
I have read a lot about Google API’s to CRUD (create, read, update and delete) contacts. There are the Contact API, the People API and other(?). What is the best way to CRUD contacts?
UserCredential credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
new ClientSecrets
{
ClientId = "xyz.apps.googleusercontent.com",
ClientSecret = " xyz"
},
new[] { "profile", "https://www.google.com/m8/feeds/contacts/xy%40gmail.com/full" },
"me",
CancellationToken.None).Result;
// Create the service.
var peopleService = new PeopleService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "WindowsClient-Google-Sync",
});
ListRequest listRequest = peopleService.People.Connections.List("people/me");
listRequest.SyncToken = null;
ListConnectionsResponse result = listRequest.Execute();
foreach (Person person in result.Connections)
{
foreach (Name name in person.Names)
{
Console.WriteLine("Name: " + name.DisplayName);
}
}
How can I extend this sample to create or update contacts?
Thanks
Andreas
If you will check Google Contacts API:
The Google Contacts API allows client applications to view and update a user's contacts. Contacts are stored in the user's Google Account; most Google services have access to the contact list.
Your client application can use the Google Contacts API to create new contacts, edit or delete existing contacts, and query for contacts that match particular criteria
Creating Contact
To create a new contact, send an authorized POST request to the user's contacts feed URL with contact data in the body.
The URL is of the form:
https://www.google.com/m8/feeds/contacts/{userEmail}/full
Upon success, the server responds with an HTTP 201 Created status code and the created contact entry with some additional elements and properties (shown in bold) that are set by the server, such as id, various link elements and properties.
import com.google.gdata.client.contacts.ContactsService;
import com.google.gdata.data.contacts.ContactEntry;
import com.google.gdata.data.contacts.ContactGroupFeed;
import com.google.gdata.data.extensions.City;
import com.google.gdata.data.extensions.Country;
import com.google.gdata.data.extensions.Email;
import com.google.gdata.data.extensions.ExtendedProperty;
import com.google.gdata.data.extensions.FormattedAddress;
import com.google.gdata.data.extensions.FullName;
import com.google.gdata.data.extensions.Im;
import com.google.gdata.data.extensions.Name;
import com.google.gdata.data.extensions.PhoneNumber;
import com.google.gdata.data.extensions.PostCode;
import com.google.gdata.data.extensions.Region;
import com.google.gdata.data.extensions.Street;
import com.google.gdata.data.extensions.StructuredPostalAddress;
// ...
public static ContactEntry createContact(ContactsService myService) {
// Create the entry to insert.
ContactEntry contact = new ContactEntry();
// Set the contact's name.
Name name = new Name();
final String NO_YOMI = null;
name.setFullName(new FullName("Elizabeth Bennet", NO_YOMI));
name.setGivenName(new GivenName("Elizabeth", NO_YOMI));
name.setFamilyName(new FamilyName("Bennet", NO_YOMI))
contact.setName(name);
contact.setContent(new PlainTextConstruct("Notes"));
// Set contact's e-mail addresses.
Email primaryMail = new Email();
primaryMail.setAddress("liz#gmail.com");
primaryMail.setDisplayName("E. Bennet");
primaryMail.setRel("http://schemas.google.com/g/2005#home");
primaryMail.setPrimary(true);
contact.addEmailAddress(primaryMail);
Email secondaryMail = new Email();
secondaryMail.setAddress("liz#example.com");
secondaryMail.setRel("http://schemas.google.com/g/2005#work");
secondaryMail.setPrimary(false);
contact.addEmailAddress(secondaryMail);
// Set contact's phone numbers.
PhoneNumber primaryPhoneNumber = new PhoneNumber();
primaryPhoneNumber.setPhoneNumber("(206)555-1212");
primaryPhoneNumber.setRel("http://schemas.google.com/g/2005#work");
primaryPhoneNumber.setPrimary(true);
contact.addPhoneNumber(primaryPhoneNumber);
PhoneNumber secondaryPhoneNumber = new PhoneNumber();
secondaryPhoneNumber.setPhoneNumber("(206)555-1213");
secondaryPhoneNumber.setRel("http://schemas.google.com/g/2005#home");
contact.addPhoneNumber(secondaryPhoneNumber);
// Set contact's IM information.
Im imAddress = new Im();
imAddress.setAddress("liz#gmail.com");
imAddress.setRel("http://schemas.google.com/g/2005#home");
imAddress.setProtocol("http://schemas.google.com/g/2005#GOOGLE_TALK");
imAddress.setPrimary(true);
contact.addImAddress(imAddress);
// Set contact's postal address.
StructuredPostalAddress postalAddress = new StructuredPostalAddress();
postalAddress.setStreet(new Street("1600 Amphitheatre Pkwy"));
postalAddress.setCity(new City("Mountain View"));
postalAddress.setRegion(new Region("CA"));
postalAddress.setPostcode(new PostCode("94043"));
postalAddress.setCountry(new Country("US", "United States"));
postalAddress.setFormattedAddress(new FormattedAddress("1600 Amphitheatre Pkwy Mountain View"));
postalAddress.setRel("http://schemas.google.com/g/2005#work");
postalAddress.setPrimary(true);
contactOne.addStructuredPostalAddress(postalAddress);
// Ask the service to insert the new entry
URL postUrl = new URL("https://www.google.com/m8/feeds/contacts/default/full");
ContactEntry createdContact = myService.insert(postUrl, contact);
System.out.println("Contact's ID: " + createdContact.getId());
return createdContact;
}
Update Contact
To update a contact, first retrieve the contact entry, modify the data and send an authorized PUT request to the contact's edit URL with the modified contact entry in the body.
The URL is of the form:
https://www.google.com/m8/feeds/contacts/userEmail/full/{contactId}
To ensure that the data sent to the API doesn't overwrite another client's changes, the contact entry's Etag should be provided in the request header.
If-Match: Etag
Upon success, the server responds with an HTTP 200 OK status code and the updated contact entry.
public static ContactEntry updateContactName(
ContactsService myService, URL contactURL)
throws ServiceException, IOException {
// First retrieve the contact to updated.
ContactEntry entryToUpdate = myService.getEntry(contactURL, ContactEntry.class);
entryToUpdate.getName().getFullName().setValue("New Name");
entryToUpdate.getName().getGivenName().setValue("New");
entryToUpdate.getName().getFamilyName().setValue("Name");
URL editUrl = new URL(entryToUpdate.getEditLink().getHref());
try {
ContactEntry contactEntry = myService.update(editUrl, entryToUpdate);
System.out.println("Updated: " + contactEntry.getUpdated().toString());
return contactEntry;
} catch (PreconditionFailedException e) {
// Etags mismatch: handle the exception.
}
return null;
}
Delete Contact
To delete a contact, send an authorized DELETE request to the contact's edit URL.
The URL is of the form:
https://www.google.com/m8/feeds/contacts/{userEmail}/full/{contactId}
To ensure that the data sent to the API doesn't overwrite another client's changes, the contact entry's Etag should be provided in the request header.
If-Match: Etag
Upon success, the server responds with an HTTP 200 OK status code.
public static void deleteContact(ContactsService myService, URL contactURL)
throws ServiceException, IOException {
// Retrieving the contact is required in order to get the Etag.
ContactEntry contact = myService.getEntry(contactURL, ContactEntry.class);
try {
contact.delete();
} catch (PreconditionFailedException e) {
// Etags mismatch: handle the exception.
}
}
while People API:
The People API lets you list authenticated users' Contacts and retrieve profile information for authenticated users and their contacts.
For example, let's say the authenticated user, Jen, has Fabian and Ranjith in her private contacts. When your app calls people.connections.list to retrieve a list of her connections, Jen is presented with a consent screen asking to give the app access to the list. If Jen consents, the app retrieves a list containing Fabian and Ranjith (with a resource name for each person). The app can then call people.get, passing in a resource name, to get private contact and public profile data for each person.