If your app reads or writes a user’s Google Calendar, OAuth is the permission boundary. The user authorizes your app, Google returns a code, and your server turns that into long-lived access. The native Google Calendar API makes you own the full OAuth flow, token refresh, scope review, and quota behavior.
Nylas hosted OAuth gives you the same user-consent model, but your app stores a grant_id instead of provider tokens. Nylas handles the Google token lifecycle behind that grant, and the same pattern works later if you add Microsoft, iCloud, or Exchange calendars.
Choose Google Calendar scopes
Section titled “Choose Google Calendar scopes”Google scopes are full URI strings. Request the smallest set that matches your feature because broader scopes add friction on the consent screen and can lengthen Google’s verification review.
| Task | Google scope |
|---|---|
| List calendars or check Free/Busy | https://www.googleapis.com/auth/calendar.readonly |
| Read events | https://www.googleapis.com/auth/calendar.events.readonly |
| Create, update, delete, or respond to event invitations | https://www.googleapis.com/auth/calendar.events |
| Manage calendars and events | https://www.googleapis.com/auth/calendar |
The granular scopes reference lists the exact scope for every Nylas calendar endpoint. Google classifies Calendar scopes as sensitive, so production apps need Google OAuth verification. If you request Gmail restricted scopes in the same connector, you may also need a security assessment.
Start the hosted OAuth flow
Section titled “Start the hosted OAuth flow”Send the user to /v3/connect/auth with your Nylas client ID, callback URI, provider, and state value. Set provider=google so the flow opens the Google consent screen.
https://api.us.nylas.com/v3/connect/auth? client_id=<NYLAS_CLIENT_ID> &redirect_uri=https://app.example.com/oauth/callback &response_type=code &provider=google &state=<SIGNED_USER_STATE>Use state to bind the callback to the user who clicked Connect. Store a signed nonce or session ID, not a raw user ID by itself. When Google redirects back, check state before exchanging the code.
The Node.js SDK can build the URL:
const authUrl = nylas.auth.urlForOAuth2({ clientId: process.env.NYLAS_CLIENT_ID, provider: "google", redirectUri: "https://app.example.com/oauth/callback", loginHint: user.email, state: signedState,});
res.redirect(authUrl);Exchange the code for a grant
Section titled “Exchange the code for a grant”After the user approves access, Google redirects to your callback with a code. Exchange it with Nylas to create the grant.
curl --request POST \ --url 'https://api.us.nylas.com/v3/connect/token' \ --header 'Authorization: Bearer <NYLAS_API_KEY>' \ --header 'Content-Type: application/json' \ --data '{ "client_id": "<NYLAS_CLIENT_ID>", "redirect_uri": "https://app.example.com/oauth/callback", "code": "<OAUTH_CODE>", "grant_type": "authorization_code" }'The response includes a grant ID. Save that ID on your user or workspace record:
{ "grant_id": "<NYLAS_GRANT_ID>", "provider": "google",}Use the grant ID for Calendar API calls. Your server authenticates with your Nylas API key, while the grant tells Nylas which Google Calendar account to act on.
curl --request GET \ --url 'https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/events?calendar_id=primary' \ --header 'Authorization: Bearer <NYLAS_API_KEY>'Handle token refresh and re-authentication
Section titled “Handle token refresh and re-authentication”Nylas refreshes the underlying Google access token for the grant, so your app doesn’t run a refresh-token job. A grant can still expire if the user revokes access, changes a password, or an admin policy invalidates tokens.
Subscribe to the grant.expired webhook and handle 401 responses on API calls. When a grant expires, send the user through hosted OAuth again. Re-authentication keeps the same account relationship and avoids losing your local sync mappings.
Fix common Google Calendar OAuth errors
Section titled “Fix common Google Calendar OAuth errors”| Error or symptom | Likely cause | Fix |
|---|---|---|
redirect_uri_mismatch | Callback URI differs from the registered URI | Match the URI exactly in Google, your Nylas app, and the auth request |
| Unverified app warning | Google OAuth consent screen isn’t verified | Add test users for development or complete Google verification |
403 after a successful connection | Connector requested read-only scope but your app calls a write endpoint | Add calendar.events or calendar, then re-authenticate the grant |
| User sees the wrong Google account | Browser session picked an existing login | Pass login_hint and let the user choose the correct account |
| Grant later expires | User or admin revoked provider access | Re-authenticate the same grant and listen for grant.expired |
The broader OAuth troubleshooting guide covers Microsoft errors and token-level failures too.
Things to know about Google Calendar OAuth
Section titled “Things to know about Google Calendar OAuth”Calendar scopes are separate from Gmail scopes. Connecting Gmail doesn’t automatically grant calendar access. Add the calendar scope before the user authenticates.
Use calendar.events.readonly when you only display events. Don’t request write scopes until your app creates, updates, deletes, or responds to event invitations.
Use service accounts only for Workspace-wide calendar access. Per-user SaaS apps usually use hosted OAuth. Google Workspace service accounts are a separate admin-controlled model, and they support Google Calendar only.
Keep the API key server-side. Browser code can start OAuth, but Calendar API requests with your Nylas API key should happen from your server.
What’s next
Section titled “What’s next”- Connect user accounts with OAuth for the provider-agnostic OAuth flow
- OAuth scopes for email and calendar for Google and Microsoft scope sets
- Google provider guide for connector setup and consent-screen requirements
- Google verification and security assessment for production approval
- Create Google calendar events after you connect the grant