I have a server application that needs to read all calendar entries of user calendars. Users have already authorized and i've stored the authcode and refresh token in my server database. Can i initialize a calendar api v3 calendarservice with the oauth2 token that i have saved? i can't figure out how to get it work without asking for user authorization at run time.
i have this working, but i can't determine how to inialize the service with a predefined token.
Dim myscopes As String() = New String() {CalendarService.Scope.Calendar} ' New () {CalendarService.Scope.Calendar}
Dim secrets As New ClientSecrets() With { _
.ClientId = rs.OAuth2Parameters.ClientId, _
.ClientSecret = rs.OAuth2Parameters.ClientSecret _
}
Dim credential As UserCredential = GoogleWebAuthorizationBroker.AuthorizeAsync(secrets, myscopes, "sellggltest1#gmail.com", System.Threading.CancellationToken.None).Result
Dim service = New CalendarService(New BaseClientService.Initializer() With { _
.HttpClientInitializer = credential, _
.ApplicationName = rs.Application _
})
Dim request As CalendarListResource.ListRequest = service.CalendarList.List()
Dim events As Data.CalendarList = request.Execute()
Related
I am trying to upload to a Google drive using Google Drive API v2, vb.net 2015,
Windows 10 Pro ver 1909. My code throws an "Error: redirect_uri_mismatch" when the following 'CreateService' procedure is called:
Public Sub CreateService()
Dim ClientId = "xxxxxxxxxxxe9gqt7105uofe6q1hmks4e89m.apps.googleusercontent.com"
Dim ClientSecret = "xxxxxxxxxxxxxxxxxxxxx"
'
Dim MyUserCredential As UserCredential = _
GoogleWebAuthorizationBroker.AuthorizeAsync(New ClientSecrets() _
With {.ClientId = ClientId, .ClientSecret = ClientSecret}, _
{DriveService.Scope.Drive}, "user", CancellationToken.None).Result
Service = New DriveService(New BaseClientService.Initializer() with _
{.HttpClientInitializer = MyUserCredential, .ApplicationName = "My Drive"})
End Sub
I am writing a windows service application in Visual Studio (VB) that polls a users google calendar for any events that are happening within the next 5 minutes.
Ideally, I'd like my service to generate the credentials, but I don't think a windows service can pop up a browser page to authenticate someone. Currently I am generating the credentials in a specific location from a console app that can pop up a browser, and having the service look for credentials in that location. I'd like to get rid of the console app altogether, but if it's necessary I'll just run it in the batch file that installs the service.
The big issue I'm having is generating the credentials file (secondary concern), and more importantly refreshing it so it doesn't expire after an hour (primary concern).
Here is my windows service code (this works perfectly fine for the hour after I run my console app and allow access to my calendar):
Dim Scopes As String() = {CalendarService.Scope.CalendarReadonly}
Dim ApplicationName As String = "Google Calendar API .NET Quickstart"
Private Sub writeUpdateTimerEvent(source As Object, e As ElapsedEventArgs)
Dim credential As UserCredential
Try
Using stream = New FileStream("FILE PATH TO client_secret.json", FileMode.Open, FileAccess.Read)
Dim credPath As String = "FILE PATH TO WHERE MY CONSOLE APP IS STORING THE CREDENTIALS FILE"
credPath = Path.Combine(credPath, ".credentials/calendar-dotnet-quickstart.json")
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(GoogleClientSecrets.Load(stream).Secrets, Scopes, "user", CancellationToken.None, New FileDataStore(credPath, True)).Result
If credential Is Nothing Then
credential.RefreshTokenAsync(CancellationToken.None)
End If
End Using
' Create Google Calendar API service.
Dim service = New CalendarService(New BaseClientService.Initializer() With {
.HttpClientInitializer = credential,
.ApplicationName = ApplicationName
})
' Define parameters of request.
Dim request As EventsResource.ListRequest = service.Events.List("primary")
request.TimeMin = DateTime.Now
request.TimeMax = DateTime.Now.AddMinutes(5)
request.ShowDeleted = False
request.SingleEvents = True
request.OrderBy = EventsResource.ListRequest.OrderByEnum.StartTime
' List events.
Dim eventsString As String = ""
Dim events As Events = request.Execute()
If events.Items IsNot Nothing AndAlso events.Items.Count > 0 Then
'This is where I do my operations on events occuring in the next 5 minutes
EventLog1.WriteEntry("Event occuring within 5 minutes")
Else
EventLog1.WriteEntry("No event occuring within 5 minutes")
End If
Catch ex As Exception
EventLog1.WriteEntry("error grabbing events." & Environment.NewLine & ex.message)
End Try
End Sub
Here is my console app code (pretty much the same as above):
Module Module1
Dim Scopes As String() = {CalendarService.Scope.CalendarReadonly}
Dim ApplicationName As String = "Google Calendar API .NET Quickstart"
Sub Main()
Dim credential As UserCredential
Using stream = New FileStream("client_secret.json", FileMode.Open, FileAccess.Read)
Dim credPath As String = "SAME FILE PATH AS IN MY SERVICE"
credPath = Path.Combine(credPath, ".credentials/calendar-dotnet-quickstart.json")
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(GoogleClientSecrets.Load(stream).Secrets, Scopes, "user", CancellationToken.None, New FileDataStore(credPath, True)).Result
Console.WriteLine(Convert.ToString("Credential file saved to: ") & credPath)
End Using
' Create Google Calendar API service.
Dim service = New CalendarService(New BaseClientService.Initializer() With {
.HttpClientInitializer = credential,
.ApplicationName = ApplicationName
})
' Define parameters of request.
Dim request As EventsResource.ListRequest = service.Events.List("primary")
request.TimeMin = DateTime.Now
request.ShowDeleted = False
request.SingleEvents = True
request.MaxResults = 10
request.OrderBy = EventsResource.ListRequest.OrderByEnum.StartTime
' List events.
Dim events As Events = request.Execute()
Console.WriteLine("Upcoming events:")
If events.Items IsNot Nothing AndAlso events.Items.Count > 0 Then
For Each eventItem As Object In events.Items
Dim [when] As String = eventItem.Start.DateTime.ToString()
If [String].IsNullOrEmpty([when]) Then
[when] = eventItem.Start.[Date]
End If
Console.WriteLine("{0} ({1})", eventItem.Summary, [when])
Next
Console.WriteLine("You may now close this window.")
System.Environment.Exit(0)
Else
Console.WriteLine("No upcoming events found.")
End If
Console.Read()
End Sub
End Module
Got it working now, using a service account instead of a user account. No need for dealing with generating credentials or refreshing the token.
Dim serviceAccountEmail As [String] = ConfigurationManager.AppSettings("ServiceAcct")
Dim certificate = New X509Certificate2("key.p12", "notasecret", X509KeyStorageFlags.Exportable)
Dim credential1 As New ServiceAccountCredential(New ServiceAccountCredential.Initializer(serviceAccountEmail) With {
.Scopes = Scopes
}.FromCertificate(certificate))
Dim service = New CalendarService(New BaseClientService.Initializer() With {
.HttpClientInitializer = credential1,
.ApplicationName = ApplicationName
})
My code is below. credential contains a token.
Settings contains a subtoken and the application name, but nothing else.
I am not sure if it is authenticating. Token, token secret, privatekey are all nothing.
Dim _Scopes As New List(Of String)
_Scopes.Add("https://www.google.com/m8/feeds")
_Scopes.Add("http://www.google.com/m8/feeds/contacts/")
_Scopes.Add("https://www.googleapis.com/auth/contacts.readonly")
Dim certificate As X509Certificate = New X509Certificate2("c:\sites\key.p12", "notasecret", X509KeyStorageFlags.Exportable)
Dim serviceAccountEmail As String = "serviceaccountemailhere"
Dim credential As ServiceAccountCredential = New ServiceAccountCredential(New ServiceAccountCredential.Initializer(serviceAccountEmail) With {.User = serviceAccountEmail, .Scopes = _Scopes}.FromCertificate(certificate))
Dim settings As RequestSettings = New RequestSettings("Gmail Contact APP", Await credential.GetAccessTokenForRequestAsync())
Dim cr As New ContactsRequest(settings)
For Each ct In cr.GetContacts.Entries
Console.Write(ct.ContactEntry.Name)
Next
Hre's my problem, i open my application in my browser and authenticate to Google. When a user access my application on his computer, he receive this error.
Google.Apis.Requests.RequestError Delegation denied for
pgsolutionssyged2#gmail.com [403] Errors [ Message[Delegation denied
for pgsolutionssyged2#gmail.com] Location[ - ] Reason[forbidden]
Domain[global] ] à
Google.Apis.Requests.ClientServiceRequest`1.Execute() dans
c:\code\google.com\google-api-dotnet-client\default\Tools\Google.Apis.Release\bin\Debug\test\default\Src\GoogleApis\Apis\Requests\ClientServiceRequest.cs:ligne
102 à ManageGoogle.LoadMailGrid(String query, String folderName)
dans C:\Workspaces\SyGED\Dev\WebAppl\Google\ManageGoogle.aspx.vb:ligne
131 à ManageGoogle.trvGMailFolders_NodeClick(Object sender,
RadTreeNodeEventArgs e) dans
C:\Workspaces\SyGED\Dev\WebAppl\Google\ManageGoogle.aspx.vb:ligne 442
à Telerik.Web.UI.RadTreeView.RaisePostBackEvent(String eventArgument)
à System.Web.UI.Page.ProcessRequestMain(Boolean
includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
In load event of my webpage i call my athenticate method like this :
Protected Sub Authenticate()
Dim datafolder As String = Server.MapPath("App_Data/GoogleService.api.auth.store")
Dim scopes As IList(Of String) = New List(Of String)()
Dim UserId As String = Context.User.Identity.Name.ToString
scopes.Add(DriveService.Scope.Drive)
scopes.Add(GmailService.Scope.MailGoogleCom)
Dim myclientsecret As New ClientSecrets() With { _
.ClientId = CLIENT_ID, _
.ClientSecret = CLIENT_SECRET _
}
Dim flow As GoogleAuthorizationCodeFlow
flow = New GoogleAuthorizationCodeFlow(New GoogleAuthorizationCodeFlow.Initializer() With { _
.DataStore = New FileDataStore(datafolder), _
.ClientSecrets = myclientsecret, _
.Scopes = scopes _
})
Dim uri As String = Request.Url.ToString()
Dim code = Request("code")
If code IsNot Nothing Then
Dim token = flow.ExchangeCodeForTokenAsync(UserId, code, uri.Substring(0, uri.IndexOf("?")), CancellationToken.None).Result
' Extract the right state.
Dim oauthState = AuthWebUtility.ExtracRedirectFromState(flow.DataStore, UserId, Request("state")).Result
Response.Redirect(oauthState)
Else
Dim result = New AuthorizationCodeWebApp(flow, uri, uri).AuthorizeAsync(UserId, CancellationToken.None).Result
If result.RedirectUri IsNot Nothing Then
' Redirect the user to the authorization server.
Response.Redirect(result.RedirectUri)
Else
' The data store contains the user credential, so the user has been already authenticated.
myDriveService = New DriveService(New BaseClientService.Initializer() With { _
.ApplicationName = "Liens Google SyGED", _
.HttpClientInitializer = result.Credential _
})
myGMailService = New GmailService(New BaseClientService.Initializer() With { _
.ApplicationName = "Liens Google SyGED", _
.HttpClientInitializer = result.Credential _
})
End If
End If
End Sub
What's wrong with my code ?
How I can do to revoke token for a user?
This is my authenticate code and I want to reset (revoke) access for one user. This is because I use the GMail API and I want allow my user to change their email if necessary.
Actually the tokens are save with login at moment where token is reach but I must change this value when user decide to change their email.
Dim datafolder As String = Server.MapPath("App_Data/GoogleService.api.auth.store")
Dim scopes As IList(Of String) = New List(Of String)()
Dim UserId As String = Context.User.Identity.Name.ToString
scopes.Add(DriveService.Scope.Drive)
scopes.Add(GmailService.Scope.MailGoogleCom)
Dim myclientsecret As New ClientSecrets() With { _
.ClientId = CLIENT_ID, _
.ClientSecret = CLIENT_SECRET _
}
Dim flow As GoogleAuthorizationCodeFlow
flow = New GoogleAuthorizationCodeFlow(New GoogleAuthorizationCodeFlow.Initializer() With { _
.DataStore = New FileDataStore(datafolder), _
.ClientSecrets = myclientsecret, _
.Scopes = scopes _
})
Dim uri As String = Request.Url.ToString()
Dim code = Request("code")
If code IsNot Nothing Then
Dim token = flow.ExchangeCodeForTokenAsync(UserId, code, uri.Substring(0, uri.IndexOf("?")), CancellationToken.None).Result
' Extract the right state.
Dim oauthState = AuthWebUtility.ExtracRedirectFromState(flow.DataStore, UserId, Request("state")).Result
Response.Redirect(oauthState)
Else
Dim result = New AuthorizationCodeWebApp(flow, uri, uri).AuthorizeAsync(UserId, CancellationToken.None).Result
If result.RedirectUri IsNot Nothing Then
' Redirect the user to the authorization server.
Response.Redirect(result.RedirectUri)
Else
' The data store contains the user credential, so the user has been already authenticated.
myDriveService = New DriveService(New BaseClientService.Initializer() With { _
.ApplicationName = "Liens Google SyGED", _
.HttpClientInitializer = result.Credential _
})
myGMailService = New GmailService(New BaseClientService.Initializer() With { _
.ApplicationName = "Liens Google SyGED", _
.HttpClientInitializer = result.Credential _
})
End If
End If
You can revoke token by making a call to https://accounts.google.com/o/oauth2/revoke?token={token}
Read https://developers.google.com/identity/protocols/OAuth2WebServer