I am getting the following error when attempting to Insert a new calendar to the user who is currently logged in. Users are able to log in and register but attempting to add a new calendar gives us this error.
Google.Apis.Requests.RequestError
Insufficient Permission [403]
Errors [
Message[Insufficient Permission] Location[ - ] Reason[insufficientPermissions] Domain[global]
]
The error occurs at the execute of the following code:
CalendarService googlecalender = new CalendarService(await (new GoogleAuthentication()).GetInitializer());
Calendar calendar = new Calendar();
calendar.Summary = "sampleCalendar";
calendar.Id = "_Sample";
calendar.Kind = "calendar#calendar";
var calendarRequest = googlecalender.Calendars.Insert(calendar);
var result = calendarRequest.Execute();
I have modified the google authentication to the following:
var authenInfo = new GoogleOAuth2AuthenticationOptions();
authenInfo.Scope.Add("openid");
authenInfo.Scope.Add("profile");
authenInfo.Scope.Add("email");
authenInfo.Scope.Add("https://www.googleapis.com/auth/plus.login");
authenInfo.Scope.Add("https://www.googleapis.com/auth/plus.me");
authenInfo.Scope.Add(YouTubeService.Scope.Youtube);
authenInfo.Scope.Add(CalendarService.Scope.Calendar);
authenInfo.Scope.Add(CalendarService.Scope.CalendarReadonly);
authenInfo.ClientId = "CLIENTID";
authenInfo.ClientSecret = "CLIENTSECRET";
authenInfo.Provider = new GoogleOAuth2AuthenticationProvider();
app.UseGoogleAuthentication(authenInfo);
and the GoogleAuthentication class is this:
public GoogleAuthentication()
{
ClientSecret = new ClientSecrets();
ClientSecret.ClientSecret = "CLIENTSECRET";
ClientSecret.ClientId = "CLIENTID";
Scope = new[] {
"https://www.googleapis.com/auth/plus.login",
YouTubeService.Scope.Youtube,
CalendarService.Scope.Calendar
};
}
private async void Authorize()
{
Credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
ClientSecret,
Scope,
"user",
CancellationToken.None
);
}
public async Task<BaseClientService.Initializer> GetInitializer()
{
if (Credential == null)
Authorize();
else if (Credential.Token.IsExpired(SystemClock.Default))
{
Boolean tokenRefreshed = await Credential.RefreshTokenAsync(CancellationToken.None);
}
return new BaseClientService.Initializer()
{
HttpClientInitializer = Credential,
ApplicationName = Properties.Settings.Default.ApplicationName
};
}
Related
I'm trying to schedule events in my O365 user calendars.
I'm using an administrator account, creating a GraphServiceClient on authentication.
There are no errors (apparently) but the event is not created. Neither on the account used nor on the Attendees.
It seems to me that the problem is in the authorization of the GraphServiceClient. I already checked in the Azure portal and the user has "Calendars.ReadWrite" permission.
Any help, please?
try
{
var scopes = new[] { "Calendars.ReadWrite.All" };
// Multi-tenant apps can use "common",
// single-tenant apps must use the tenant ID from the Azure portal
var tenantId = "common";
Configuracoes Dados = new Configuracoes();
// Values from app registration
string clientId = Dados.EMailCV.ToString();
string clientSecret = Dados.PasswordCV.ToString();
// using Azure.Identity;
var options = new TokenCredentialOptions
{
AuthorityHost = AzureAuthorityHosts.AzurePublicCloud
};
// This is the incoming token to exchange using on-behalf-of flow
var oboToken = "JWT_TOKEN_TO_EXCHANGE";
var cca = ConfidentialClientApplicationBuilder
.Create(clientId)
.WithTenantId(tenantId)
.WithClientSecret(clientSecret)
.Build();
// DelegateAuthenticationProvider is a simple auth provider implementation
// that allows you to define an async function to retrieve a token
// Alternatively, you can create a class that implements IAuthenticationProvider
// for more complex scenarios
var authProvider = new DelegateAuthenticationProvider(async (request) =>
{
// Use Microsoft.Identity.Client to retrieve token
var assertion = new UserAssertion(oboToken);
var result = await cca.AcquireTokenOnBehalfOf(scopes, assertion).ExecuteAsync();
request.Headers.Authorization =
new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", result.AccessToken);
});
GraphServiceClient graphClient = new GraphServiceClient(authProvider);
var #event = new Event
{
Subject = "Let's go for lunch",
Body = new ItemBody
{
ContentType = BodyType.Html,
Content = "Does noon work for you?"
},
Start = new DateTimeTimeZone
{
DateTime = "2022-11-04T12:00:00",
TimeZone = "GMT Standard Time"
},
End = new DateTimeTimeZone
{
DateTime = "2017-04-15T14:00:00",
TimeZone = "GMT Standard Time"
},
// Location = new Location
// {
// displayName = "Harry's Bar"
// },
Attendees = new List<Attendee>()
{
new Attendee
{
EmailAddress = new EmailAddress
{
Address = "p560#esenviseu.net",
Name = "Nuno Barros"
},
Type = AttendeeType.Required
}
},
AllowNewTimeProposals = true,
IsOnlineMeeting = true,
OnlineMeetingProvider = OnlineMeetingProviderType.TeamsForBusiness
};
graphClient.Me.Events
.Request()
.Header("Prefer", "outlook.timezone=\"GMT Standard Time\"")
.AddAsync(#event);
}
catch (Exception ex)
{
lblTexto.Text = "Erros!<br>" + ex.Message;
}
finally
{
lblTexto.Text = "Sem erros!";
}
Well.. I'm trying this code to create an Event
CalendarService service;
GoogleCredential credential;
try
{
string[] scopes = new string[] { CalendarService.Scope.Calendar };
using (var stream = new FileStream(#"C:\Prueba\meet.json", FileMode.Open, FileAccess.Read))
{
credential = GoogleCredential.FromStream(stream)
.CreateScoped(scopes);
}
service = new CalendarService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential
});
Event calendarEvent = new Event();
DateTime start = DateTime.Now;
calendarEvent.Kind = "";
calendarEvent.Summary = "prueba";
calendarEvent.Status = "confirmed";
calendarEvent.Visibility = "public";
calendarEvent.Description = "prueba";
calendarEvent.Creator = new Event.CreatorData
{
Email = "email#example.com", //email#example.com
Self = true
};
calendarEvent.Organizer = new Event.OrganizerData
{
Email = "email#example.com",
Self = true
};
calendarEvent.Start = new EventDateTime
{
DateTime = start,
TimeZone = "America/Mexico_City"
};
calendarEvent.End = new EventDateTime
{
DateTime = start.AddHours(1),
TimeZone = "America/Mexico_City"
};
calendarEvent.Recurrence = new String[] { "RRULE:FREQ=DAILY;COUNT=1" };
calendarEvent.Sequence = 0;
calendarEvent.HangoutLink = "";
calendarEvent.ConferenceData = new ConferenceData
{
CreateRequest = new CreateConferenceRequest
{
RequestId = "1234abcdef",
ConferenceSolutionKey = new ConferenceSolutionKey
{
Type = "hangoutsMeet"
},
Status = new ConferenceRequestStatus
{
StatusCode = "success"
}
},
EntryPoints = new List<EntryPoint>
{
new EntryPoint
{
EntryPointType = "video",
Uri = "",
Label = ""
}
},
ConferenceSolution = new ConferenceSolution
{
Key = new ConferenceSolutionKey
{
Type = "hangoutsMeet"
},
Name = "Google Meet",
IconUri = ""
},
ConferenceId = ""
};
//calendarEvent.EventType = "default";
EventsResource.InsertRequest request = service.Events.Insert(calendarEvent, "email#example.com");
request.ConferenceDataVersion = 0;
Event createEvent = request.Execute();
string url = createEvent.HangoutLink;
}
catch (Exception ex)
{
}
The source code is here
When I execute the line 116: Event createEvent = request.Execute();
I get this error: Google.Apis.Requests.RequestError Invalid conference type value. [400] Errors [Message[Invalid conference type value.] Location[ - ] Reason[invalid] Domain[global]
I don't know what means this error o with line I wrong
Could anyone help me with an example to create an event using classes C# from Google API Calendar?
As described in the C# library documentation for createRequest:
Either conferenceSolution and at least one entryPoint, or createRequest is required.
This means that you should use only CreateConferenceRequest as this conference is brand new (if it already existed then you would be wanting to use ConferenceSolution along with EntryPoints ). Therefore, simply remove ConferenceSolution and EntryPoints to leave just CreateConferenceRequest which as specified in the documentation is used for generating a new conference and attach it to the event.
I'm integrate google calendar api in aps.net mvc application .
I get error "The access token has expired and could not be refreshed. Errors: refresh error, refresh error, refresh error".
the code work correctly when run it on localhost but when I run it on server I have the above error
the code is
public async Task< ActionResult> Index()
{
var userId = User.Identity.GetUserId();
var _User = "Usr" + userId;
string credPath = Server.MapPath($"~/UsersToken/{_User}");
UserCredential UsrCred = null;
FileDataStore fileStore = new FileDataStore(credPath);
TokenResponse tokenResponse = await fileStore.GetAsync<TokenResponse>(userId);
if (!Directory.Exists(credPath))
{
Directory.CreateDirectory(credPath);
}
DirectoryInfo info = new DirectoryInfo(credPath);
DirectorySecurity security = info.GetAccessControl();
security.AddAccessRule(new FileSystemAccessRule("Users", FileSystemRights.FullControl, AccessControlType.Allow));
info.SetAccessControl(security);
if (tokenResponse == null)
{
var result = new AuthorizationCodeMvcApp(this, new AppFlowMetadata()).AuthorizeAsync(CancellationToken.None);
if (result.Result.Credential == null) // <<- it's always true, so it always gets redirected
return Redirect(result.Result.RedirectUri);
else
{
UsrCred = result.Result.Credential;
}
}
else
{
IAuthorizationCodeFlow flow =
new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer
{
ClientSecrets = new ClientSecrets
{
ClientId = _clientId,
ClientSecret = _clientSecret
},
Scopes = Scopes,
DataStore = new FileDataStore(credPath, true)
//DataStore = new FileDataStore(Google.Apis.Auth)
});
UsrCred = new UserCredential(flow, userId, tokenResponse);
}
// Create Google Calendar API service.
var service = new CalendarService(new BaseClientService.Initializer()
{
HttpClientInitializer = UsrCred,
ApplicationName = ApplicationName,
});
// Define parameters of request.
EventsResource.ListRequest request = service.Events.List("primary");
request.TimeMin = DateTime.Now;
request.ShowDeleted = false;
request.SingleEvents = true;
request.OrderBy = EventsResource.ListRequest.OrderByEnum.StartTime;
Events events = request.Execute();
List<EventModel> Result = new List<EventModel>();
if (events.Items != null && events.Items.Count > 0)
{
foreach (var eventItem in events.Items)
{
Result.Add(
new EventModel()
{
Sumarry = eventItem.Summary,
Description = eventItem.Description,
StartDate = eventItem.Start.DateTime,
EndDate = eventItem.End.DateTime,
GoogleMeetLink = eventItem.HangoutLink
}
);
}
}
else
{
//Console.WriteLine("No upcoming events found.");
}
return View(Result);
}
the redirect_url method is
public async Task<ActionResult> IndexAsyc(string state, string code, string scope)
{
string Lang = ViewBag.Lang ?? "ar";
string RedirectURL = HttpContext.Request.Url.GetLeftPart(UriPartial.Authority) + $"/{Lang}/Meetings/IndexAsyc";
var userId = User.Identity.GetUserId();
var _User = "Usr" + userId;
string credPath = Server.MapPath($"~/UsersToken/{_User}");
UserCredential UsrCred = null;
FileDataStore fileStore = new FileDataStore(credPath);
TokenResponse tokenResponse = await fileStore.GetAsync<TokenResponse>(userId);
// create authorization code flow with clientSecrets
GoogleAuthorizationCodeFlow authorizationCodeFlow = new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer
{
DataStore = new FileDataStore(credPath),
ClientSecrets = new ClientSecrets()
{
ClientId = _clientId,
ClientSecret = _clientSecret
},
Scopes = Scopes
});
//var result = new AuthorizationCodeMvcApp(this, new AppFlowMetadata()).AuthorizeAsync(CancellationToken.None);
if (tokenResponse == null)
{
// token data does not exist for this user
tokenResponse = await authorizationCodeFlow.ExchangeCodeForTokenAsync(
userId, // user for tracking the userId on our backend system
code,
RedirectURL, // redirect_uri can not be empty. Must be one of the redirects url listed in your project in the api console
CancellationToken.None);
}
TokenResponse tokenResponse2 = await fileStore.GetAsync<TokenResponse>(userId);
if (tokenResponse2 != null)
{
return RedirectToAction("Index");
}
var Creds = new UserCredential(authorizationCodeFlow, userId, tokenResponse2);
if (Creds != null) // result.Credential != null )
{
var service = new CalendarService(new BaseClientService.Initializer()
{
HttpClientInitializer = Creds,//result.Credential,
ApplicationName = ApplicationName,
});
return RedirectToAction("Index");
}
else
{
return new RedirectResult(RedirectURL);
}
}
how can I set token not expire never ?
My application used to work just fine, but yesterday starts to give me an error when I try to open a push notification channel via Google Drive .NET SDK, the error is:
Failed to create channel [400]
Message[Failed to create channel]
Location[ - ]
Reason[invalidArgument]
Domain[global]
You can see my code here:
public async Task<Channel> StartWebHookWatch(TokenResponse token, string userId, string channelId, string pageToken, string urlCallBack)
{
var service = GetDriveService(token);
var expireDate = DateTime.UtcNow.AddSeconds(604800); // 1 Week
var channel = new Channel()
{
Id = channelId, // Just a Guid created with "Guid.NewGuid().ToString();"
Token = userId, // Just a Id to bind the channel With My appUser
Type = "web_hook",
Address = urlCallBack, // Authorized Url
Expiration = (long)expireDate.Subtract(new DateTime(1970, 1, 1, 0, 0, 0)).TotalMilliseconds
};
return await service.Changes.Watch(channel, pageToken).ExecuteAsync();
}
private DriveService GetDriveService(TokenResponse token)
{
return new DriveService(new BaseClientService.Initializer()
{
HttpClientInitializer = new UserCredential(
new GoogleAuthorizationCodeFlow(
new GoogleAuthorizationCodeFlow.Initializer() { ClientSecrets = ClientSecret }),
ClientSecret.ClientId, token),
ApplicationName = AppName
});
}
I just did a lot of tests and I don't find even a clue what is the problem...
I appreciate some help to solve this, Thank you, guys.
In Google Cloud Platform the DataProc API is enabled. I am using the same key I use to access GCS and Big query to create a new cluster per this example. I get a Request had insufficient authentication scopes error on the following line.
Operation createOperation =
service.Projects.Regions.Clusters.Create(newCluster, project, dataprocGlobalRegion).Execute();
My complete code:
public static class DataProcClient
{
public static void Test()
{
string project = ConfigurationManager.AppSettings["Google.ProjectName"]; ;
string dataprocGlobalRegion = "global";
string zone = "us-east1-b";
string machineType = "n1-standard-4";
string clusterName = "sample-cluster";
int numWorkers = 2;
String serviceAccountEmail= ConfigurationManager.AppSettings["Google.ServiceAccountEmail"];
String certificateFile = ConfigurationManager.AppSettings["KeyDirectory"] + ConfigurationManager.AppSettings["Google.CertificateFile"];
X509Certificate2 certificate = new X509Certificate2(certificateFile, "notasecret", X509KeyStorageFlags.Exportable);
ServiceAccountCredential credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(serviceAccountEmail)
{
Scopes = new[] { StorageService.Scope.DevstorageFullControl }
}.FromCertificate(certificate));
DataprocService service = new DataprocService(
new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "Dataproc Sample",
});
// Create a new cluster:
Cluster newCluster = new Cluster
{
ClusterName = clusterName,
Config = new ClusterConfig
{
GceClusterConfig = new GceClusterConfig
{
ZoneUri = String.Format(
"https://www.googleapis.com/compute/v1/projects/{0}/zones/{1}",
project, zone),
},
MasterConfig = new InstanceGroupConfig
{
NumInstances = 1,
MachineTypeUri = String.Format(
"https://www.googleapis.com/compute/v1/projects/{0}/zones/{1}/machineTypes/{2}",
project, zone, machineType),
},
WorkerConfig = new InstanceGroupConfig
{
NumInstances = numWorkers,
MachineTypeUri = String.Format(
"https://www.googleapis.com/compute/v1/projects/{0}/zones/{1}/machineTypes/{2}",
project, zone, machineType),
},
},
};
Operation createOperation =
service.Projects.Regions.Clusters.Create(newCluster, project, dataprocGlobalRegion).Execute();
// Poll the operation:
while (!IsDone(createOperation))
{
Console.WriteLine("Polling operation {0}", createOperation.Name);
createOperation =
service.Projects.Regions.Operations.Get(createOperation.Name).Execute();
Thread.Sleep(1000);
}
}
static bool IsDone(Operation op)
{
return op.Done ?? false;
}
}
When creating your ServiceAccountCredential, change:
new[] { StorageService.Scope.DevstorageFullControl }
to:
new[] { DataprocService.Scope.CloudPlatform }