OAuth
Secure connections between users and their calendar providers.
Understanding OAuth Operations
The OAuth API manages secure connections between your users and their calendar providers (Google, Microsoft). It handles the complex authentication flows, token management, and permission scopes needed to access calendar data, providing a seamless integration experience for your application.
OAuth (Open Authorization) is the industry standard for secure API access. In calendar applications, OAuth enables:
Secure Access: Users grant your application permission to access their calendars without sharing passwords
Token Management: Automatic handling of access tokens, refresh tokens, and expiration cycles
Prerequisites
Before implementing OAuth, ensure you have:
- Created a user using the Users API
- Configured OAuth providers (Google, Microsoft) in your Recal dashboard
- Set up redirect URLs in both the OAuth provider's dashboard and Recal dashboard
Understanding Tokens
OAuth uses two types of tokens to manage access:
Access Tokens
- Purpose: Used to make API calls to access the user's calendar data
- Lifespan: Valid for 1 hour
- Usage: Include in API requests to authenticate and authorize calendar operations
Refresh Tokens
- Purpose: Used to obtain new access tokens when they expire
- Lifespan: Valid for 30 days (varies by provider)
- Usage: Automatically handled by the system to maintain continuous access
Important: Access tokens expire frequently for security reasons. Refresh tokens allow your application to maintain access without requiring users to re-authenticate constantly.
OAuth Flow Overview
The OAuth process consists of two main steps:
- Authorization: Generate an OAuth link and redirect the user to the provider's authorization page
- Token Exchange: Verify the authorization code and receive access/refresh tokens
User → OAuth Link → Provider Authorization → Callback → Token Verification → Access Granted
Step 1: Generate OAuth Link
Single Provider Link
// Get OAuth authorization URL (with defaults)
const link = await recal.oauth.getAuthLink(
'user_id',
'google'
)
console.log(link.url) // Use this URL to redirect user
// Or with custom options
const linkWithOptions = await recal.oauth.getAuthLink(
'user_id',
'google',
{
scope: 'write', // 'write', 'read', or 'free-busy'
accessType: 'offline', // 'offline' or 'online'
redirectUrl: 'https://app.example.com/callback' // optional
}
)Multiple Provider Links
// Get OAuth URLs for all providers
const links = await recal.oauth.getAuthLinks('user_id')
console.log(links.google.url)
console.log(links.microsoft.url)
// Or with specific providers and options
const linksFiltered = await recal.oauth.getAuthLinks(
'user_id',
{
provider: ['google', 'microsoft'],
scope: 'write',
accessType: 'offline'
}
)Configuration Options
scope: Determines the level of access your application requests
write: Read/write access to events (create, modify, delete events). Also accepts deprecatededit.read: Read-only access to calendars and eventsfree-busy: Read-only access to busy/free time information (no event details)
For detailed information on how scopes map to provider-specific permissions, see the OAuth setup guide.
Upgrading Scopes: If you need to add more scopes to your application (e.g., upgrading from free-busy to write), all existing users who authenticated with the previous scope level will need to re-authenticate. Their current OAuth connections will continue working but will only have access to the original scopes they granted. Plan scope requirements carefully before your initial launch to minimize user disruption.
accessType: Controls token types and session duration
offline: Returns both access and refresh tokens (recommended for server applications). Connections remain active beyond the initial 30-minute access token expiration through automatic token refresh.online: Returns only access tokens (suitable for client-side applications). Sessions expire after 30 minutes.
redirectUrl (optional):
- The URL where users are redirected after authorization
- Should be a callback endpoint/page in your application that can handle the authorization response code
- If not provided, uses the default redirect URL configured in your Recal dashboard
- Must match URLs configured in your OAuth provider's dashboard
- For local development, pass a different
redirectUrlwithout changing your dashboard settings
Step 2: Handle OAuth Callback
After the user completes authorization, they're redirected to your callback URL with query parameters:
code: Authorization code to exchange for tokensstate: Base64URL encoded string containing the user ID (for security)scope: Space-separated list of granted scopes from the provider
Verify Authorization Code
// Extract parameters from callback URL (frontend)
const urlParams = new URLSearchParams(window.location.search)
const code = urlParams.get('code')
const state = urlParams.get('state')
const scope = urlParams.get('scope')?.split(' ') || [] // Provider returns space-separated scopes
// Verify OAuth code from callback (backend)
const result = await recal.oauth.verifyCode(
'google',
{
code: code, // Authorization code from callback URL
state: state, // State parameter from callback URL
scope: scope // Array of granted scopes (required)
},
{
redirectUrl: 'https://app.example.com/callback' // Must match redirectUrl used in getAuthLink()
}
)Security Note: Always verify the state parameter matches what you expect to prevent CSRF attacks.
Managing OAuth Connections
Once established, OAuth connections can be managed through various operations:
Retrieve Connections
Want to migrate from Recal to another system? We allow you to get the OAuth connections for a user so you can migrate without having to re-authenticate them.
// Get all OAuth connections for a user (tokens hidden by default)
const connections = await recal.oauth.list('user_id')
// Get with full token details
const connectionsWithTokens = await recal.oauth.list('user_id', {
showToken: 'true'
})
// Get specific provider connection
const googleConnection = await recal.oauth.get('user_id', 'google')
// Get with full token details
const googleConnectionFull = await recal.oauth.get('user_id', 'google', {
showToken: 'true'
})Bring Your Own Tokens
Migrating from another system to Recal? If you already have a user's refresh and access token, you can set them manually using the create method. This way, your users don't have to re-authenticate.
// Set OAuth tokens manually (useful for migrations or testing)
const connection = await recal.oauth.create(
'user_id',
'google',
{
accessToken: 'access_token_here',
refreshToken: 'refresh_token_here', // optional but recommended
scope: ['calendar.events', 'calendar.readonly'],
expiresAt: new Date('2024-12-31'), // optional
email: 'user@example.com' // optional
}
)Disconnect Provider
// Remove OAuth connection for a provider
await recal.oauth.delete('user_id', 'google')Get a Fresh Access Token
Recal handles all the token refresh logic for you, but in some cases, you might want to get a fresh access token for a user.
For example, you might be using Recal to integrate calendars into your product, but you also want to integrate with other services like Google Drive or Outlook Mail.
In order to make calls to other Google services, you need to get a fresh access token for the user. You can do this by calling the getFreshAccessToken method.
To integrate with other Google services, you need to make sure your OAuth provider app is configured to have the required scopes.
// Get a fresh access token for a user for a specific provider
const tokenData = await recal.oauth.getFreshAccessToken('user_id', 'google')
console.log(tokenData.accessToken)
console.log(tokenData.expiresAt)
// Use this token for other Google/Microsoft servicesBest Practices
- Use Offline Access: Always request
accessType: 'offline'for server-side applications. This provides refresh tokens that keep connections active beyond the 30-minute access token expiration through automatic renewal with a refresh token. - Request Minimum Scope: Only request the scope you need (
free-busy<read<write) - Verify State Parameter: Always validate the state parameter in callbacks to prevent CSRF attacks
- Handle Expiration: Recal automatically refreshes tokens, but be prepared to handle re-authentication flows
- Secure Token Storage: Never expose full tokens in client-side code - avoid using
showToken: 'true'in production - Match Redirect URLs: Ensure redirect URLs match exactly between OAuth provider dashboard, Recal dashboard, and your code
- Test Both Providers: Google and Microsoft have slightly different OAuth behaviors - test both thoroughly
Related
- See Error Handling for handling SDK errors
- See Users for managing users
- See Events for working with calendar events