Calendar Sync
Connect your Google Calendar or Microsoft Outlook calendar to Olyron so your upcoming meetings appear alongside your book of business. Calendar Sync uses standard OAuth, stores a per-user connection, and caches events locally so the Organizer and Calendar views can render your day without hitting the provider on every load.
#What Calendar Sync does
Calendar Sync links each advisor's Olyron account to an external calendar provider through OAuth. Once connected, Olyron holds an access token (and refresh token) for that provider and keeps a local cache of your events in the calendar_events_cache table so views like the Organizer and the Calendar page can read your schedule quickly.
Two providers are supported today, selected by the provider query parameter on the connect endpoint:
| Provider | provider value | Token endpoint | Identity source |
|---|---|---|---|
| Google Calendar | oauth2.googleapis.com/token | googleapis.com/oauth2/v2/userinfo (email) | |
| Microsoft Outlook | outlook | login.microsoftonline.com/common/oauth2/v2.0/token | graph.microsoft.com/v1.0/me (mail / userPrincipalName) |
(user_id, provider) — the calendar_connections table has a unique constraint on that pair, and saving re-uses (upserts) the existing row. Reconnecting the same provider updates tokens in place rather than creating a duplicate.#Connecting a calendar
Connecting is a standard OAuth redirect flow. Your browser hits Olyron's connect endpoint, gets bounced to Google or Microsoft to grant access, and is returned to Olyron where the connection is saved.
- 1Start the flowOpen
GET /api/calendar/connect?provider=google(orprovider=outlook). You must be signed in — the endpoint returns 401Unauthorizedotherwise, and 400 for any provider other thangoogleoroutlook. - 2Choose where to land afterwardAdd
&redirect=/dashboard/calendarto control where you end up after connecting. If omitted, the flow defaults to/dashboard/organizer. - 3Grant access at the providerOlyron redirects you to the provider's consent screen with a signed
statetoken (a base64 blob carrying your user id, the redirect path, and a timestamp). Approve the requested calendar scopes. - 4Return to OlyronThe provider calls back to
/api/calendar/google/callbackor/api/calendar/outlook/callback. Olyron exchanges the authorization code for tokens, reads your provider email, and upserts the connection withis_activeandsync_enabledset to true. - 5Confirm successYou are redirected to your chosen page with
?calendar_connected=google(oroutlook) appended to the URL — use that flag to show a success toast.
# Connect Google Calendar, return to the Calendar page
GET /api/calendar/connect?provider=google&redirect=/dashboard/calendar
# Connect Outlook, return to the Organizer (default redirect)
GET /api/calendar/connect?provider=outlook#Sync scope and permissions
Sync is currently one-way and read-only: Olyron reads your calendar, it does not write events back to Google or Outlook. The OAuth scopes requested reflect that — no write or modify scope is asked for.
| Provider | Scopes requested |
|---|---|
| calendar.readonly, calendar.events.readonly, userinfo.email | |
| Outlook | openid, email, offline_access, Calendars.Read |
The Google flow requests access_type=offline with prompt=consent, and Outlook requests offline_access, so both return a refresh token. Olyron stores access_token, refresh_token, and a computed token_expires_at (derived from the provider's expires_in) on the connection row.
#How events are cached and read
A sync run (syncCalendar) fetches events for the window from today through the next 30 days and upserts them into calendar_events_cache, keyed on (connection_id, external_id). The connection's last_sync_at is stamped on success, and any failure message is written to sync_error for troubleshooting.
Reads never call the provider directly — they query the local cache. getTodaysEvents returns non-cancelled events between midnight and midnight for the signed-in user, and getEvents(start, end) returns a custom range. Both join calendar_connections to attach the provider label to each event.
titletext- Event subject line from the provider.
start_time / end_timetimestamptz- Event bounds; queries filter and order on start_time.
is_all_dayboolean- True for all-day events.
timezonetext | null- Event timezone as reported by the provider.
locationtext | null- Meeting location or link.
organizer_emailtext | null- Email of the organizer.
attendeesCalendarAttendee[]- List of { email, name?, status? } where status is accepted / declined / tentative / needsAction.
statusconfirmed | tentative | cancelled- Cancelled events are excluded from event reads.
is_recurring / recurrence_ruleboolean / text- Recurrence flag and RRULE string when present.
external_idtext- Provider's event id; part of the cache upsert key with connection_id.
fetchGoogleEvents calls the Google Calendar API and fetchOutlookEvents calls Microsoft Graph. Synced events land in calendar_events_cache and surface on /dashboard/calendar and /dashboard/organizer. OAuth client credentials must be configured in the environment for each provider.#Managing and disconnecting
Each user's connections are private to them and scoped to their tenant. Row-Level Security on calendar_connections and calendar_events_cache restricts every row to its owning user_id, so no advisor can see another's calendar.
- Active connections are those with
is_active = true; the connection list query filters on that flag. - Disconnecting sets both
is_activeandsync_enabledto false and deletes that provider's cached events, so your schedule stops appearing in Olyron immediately. - Your calendars surface in the UI at
/dashboard/calendar(month view plus a per-calendar toggle list) and feed the/dashboard/organizerview.
#Configuration and troubleshooting
Required environment variables
NEXT_PUBLIC_APP_URLstring- Base app URL; used to build every OAuth redirect_uri and the return redirects.
NEXT_PUBLIC_GOOGLE_CLIENT_IDstring- Google client id used to build the authorization URL (client-visible).
GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRETstring- Server-side credentials used in the Google token exchange.
NEXT_PUBLIC_MICROSOFT_CLIENT_IDstring- Microsoft client id used to build the authorization URL (client-visible).
MICROSOFT_CLIENT_ID / MICROSOFT_CLIENT_SECRETstring- Server-side credentials used in the Outlook token exchange.
${NEXT_PUBLIC_APP_URL}/api/calendar/google/callback and ${NEXT_PUBLIC_APP_URL}/api/calendar/outlook/callback in the Google Cloud and Azure app registrations. A mismatch produces a token_exchange_failed redirect.Error redirects you may see
| Query flag on return URL | Meaning | What to do |
|---|---|---|
| error=oauth_failed | Provider returned an OAuth error (e.g. consent denied). | Retry and approve the requested scopes. |
| error=missing_params | Callback arrived without a code or state. | Restart from /api/calendar/connect. |
| error=invalid_state | The state token could not be decoded. | Restart the flow; do not reuse an old link. |
| error=token_exchange_failed | Code-for-token exchange failed at the provider. | Check client id/secret and the registered redirect URI. |
| error=connection_failed | Unexpected error while saving the connection. | Retry; check server logs for the [Google Calendar] / [Outlook Calendar] callback error. |
| error=session_expired | Your Olyron session ended mid-flow (redirects to /sign-in). | Sign in again, then reconnect. |