Integrating Google Calendar API into Windows Service Application

I’m building a Windows service using VB.NET that needs to check a user’s Google Calendar every few minutes to find upcoming appointments within a 10-minute window.

Current Setup Issues

Right now I have two separate applications. My main service can’t show browser windows for OAuth authentication, so I created a console application that handles the authentication flow and saves credentials to a shared folder. The service then reads these saved credentials.

Main Problems

  1. Token expiration - My biggest headache is that tokens expire after about an hour and the service stops working
  2. Initial authentication - Having to run a separate console app feels clunky

Windows Service Code (VB.NET)

Dim ApiScopes As String() = {CalendarService.Scope.CalendarReadonly}
Dim AppName As String = "Calendar Monitor Service"

Private Sub CheckCalendarEvents(sender As Object, args As ElapsedEventArgs)
    Dim userCred As UserCredential
    
    Try
        Using fileStream = New FileStream("C:\Config\client_secrets.json", FileMode.Open, FileAccess.Read)
            Dim tokenPath As String = "C:\Tokens"
            tokenPath = Path.Combine(tokenPath, ".auth/calendar-service.json")
            
            userCred = GoogleWebAuthorizationBroker.AuthorizeAsync(
                GoogleClientSecrets.Load(fileStream).Secrets, 
                ApiScopes, 
                "serviceuser", 
                CancellationToken.None, 
                New FileDataStore(tokenPath, True)).Result
                
            If userCred Is Nothing Then
                userCred.RefreshTokenAsync(CancellationToken.None)
            End If
        End Using
        
        Dim calendarService = New CalendarService(New BaseClientService.Initializer() With {
            .HttpClientInitializer = userCred,
            .ApplicationName = AppName
        })
        
        Dim eventsQuery As EventsResource.ListRequest = calendarService.Events.List("primary")
        eventsQuery.TimeMin = DateTime.Now
        eventsQuery.TimeMax = DateTime.Now.AddMinutes(10)
        eventsQuery.ShowDeleted = False
        eventsQuery.SingleEvents = True
        eventsQuery.OrderBy = EventsResource.ListRequest.OrderByEnum.StartTime
        
        Dim calendarEvents As Events = eventsQuery.Execute()
        
        If calendarEvents.Items IsNot Nothing AndAlso calendarEvents.Items.Count > 0 Then
            ServiceEventLog.WriteEntry("Found upcoming appointments")
        Else
            ServiceEventLog.WriteEntry("No appointments in next 10 minutes")
        End If
        
    Catch ex As Exception
        ServiceEventLog.WriteEntry("Calendar check failed: " & ex.Message)
    End Try
End Sub

Console App for Authentication

Module AuthModule
    Dim Permissions As String() = {CalendarService.Scope.CalendarReadonly}
    Dim ProgramName As String = "Calendar Auth Helper"
    
    Sub Main()
        Dim authCredential As UserCredential
        
        Using configStream = New FileStream("client_secrets.json", FileMode.Open, FileAccess.Read)
            Dim credentialStorage As String = "C:\Tokens"
            credentialStorage = Path.Combine(credentialStorage, ".auth/calendar-service.json")
            
            authCredential = GoogleWebAuthorizationBroker.AuthorizeAsync(
                GoogleClientSecrets.Load(configStream).Secrets, 
                Permissions, 
                "serviceuser", 
                CancellationToken.None, 
                New FileDataStore(credentialStorage, True)).Result
                
            Console.WriteLine("Authentication saved to: " & credentialStorage)
        End Using
        
        Dim apiService = New CalendarService(New BaseClientService.Initializer() With {
            .HttpClientInitializer = authCredential,
            .ApplicationName = ProgramName
        })
        
        Dim testQuery As EventsResource.ListRequest = apiService.Events.List("primary")
        testQuery.TimeMin = DateTime.Now
        testQuery.ShowDeleted = False
        testQuery.SingleEvents = True
        testQuery.MaxResults = 5
        testQuery.OrderBy = EventsResource.ListRequest.OrderByEnum.StartTime
        
        Dim testResults As Events = testQuery.Execute()
        Console.WriteLine("Recent events:")
        
        If testResults.Items IsNot Nothing AndAlso testResults.Items.Count > 0 Then
            For Each appointment As Object In testResults.Items
                Dim eventTime As String = appointment.Start.DateTime.ToString()
                If String.IsNullOrEmpty(eventTime) Then
                    eventTime = appointment.Start.Date
                End If
                Console.WriteLine("{0} - {1}", appointment.Summary, eventTime)
            Next
            Console.WriteLine("Authentication successful. Press any key to exit.")
        Else
            Console.WriteLine("No events found but authentication worked.")
        End If
        
        Console.ReadKey()
    End Sub
End Module

Is there a better way to handle token refresh automatically in the service? Should I be using service accounts instead?