Add auto-refresh for Cal.com OAuth access tokens#57
Conversation
|
Important Review skippedBot user detected. To trigger a single review, invoke the You can disable this status message by setting the WalkthroughIntroduces automatic token refresh infrastructure by adding a new Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant BookingAction as booking action
participant GetValidAccessToken as getValidAccessToken()
participant DB as Database
participant CalComAPI as Cal.com API
Client->>BookingAction: Request with userId
BookingAction->>GetValidAccessToken: getValidAccessToken(userId)
GetValidAccessToken->>DB: Fetch account token & expiry
alt Token expired or expiring soon
GetValidAccessToken->>DB: Fetch refresh token
GetValidAccessToken->>CalComAPI: POST refreshToken endpoint
CalComAPI-->>GetValidAccessToken: New access token + metadata
GetValidAccessToken->>DB: Update with new token & expiry
GetValidAccessToken-->>BookingAction: New access token
else Token still valid
GetValidAccessToken-->>BookingAction: Existing access token
end
BookingAction-->>Client: Response with valid token
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes
Suggested labels
Poem
Pre-merge checks and finishing touches✅ Passed checks (4 passed)
Comment |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Co-authored-by: zhyd1997 <31362988+zhyd1997@users.noreply.github.com>
Co-authored-by: zhyd1997 <31362988+zhyd1997@users.noreply.github.com>
Co-authored-by: zhyd1997 <31362988+zhyd1997@users.noreply.github.com>
Co-authored-by: zhyd1997 <31362988+zhyd1997@users.noreply.github.com>
Co-authored-by: zhyd1997 <31362988+zhyd1997@users.noreply.github.com>
|
@copilot Default access_token expires_in is 30 min if not provided |
Co-authored-by: zhyd1997 <31362988+zhyd1997@users.noreply.github.com>
Updated to use 30-minute default expiry when Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
lib/auth/refresh-token.ts (1)
164-174: Consider race conditions for concurrent refresh attempts.While the current implementation is functionally correct, concurrent calls to refresh the same user's token could result in race conditions where one refresh overwrites another. This is generally acceptable for token refresh scenarios, but consider adding a note or implementing optimistic locking if this becomes an issue in production.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
AGENTS.md(2 hunks)README.md(1 hunks)app/(dashboard)/bookings/actions.ts(2 hunks)constants/oauth.ts(1 hunks)lib/auth/refresh-token.ts(1 hunks)
🔇 Additional comments (10)
constants/oauth.ts (1)
20-20: LGTM!The new constant is correctly defined and follows the established naming pattern for OAuth endpoints.
AGENTS.md (2)
26-27: LGTM!The code map entries accurately document the new refresh token infrastructure and its integration points.
Also applies to: 32-32
65-72: LGTM!Comprehensive documentation of the token refresh feature with clear guidance for developers integrating Cal.com API access.
app/(dashboard)/bookings/actions.ts (2)
15-15: LGTM!The import correctly brings in the new centralized token management helper.
40-41: Clean integration with centralized token management.The code correctly delegates token retrieval to
getValidAccessToken, which handles automatic refresh transparently. Error handling is properly managed through the catch blocks in the action functions.lib/auth/refresh-token.ts (4)
8-24: LGTM!The constants and Zod schema are well-defined:
- 5-minute expiry buffer provides good protection against edge cases
- 30-minute default aligns with Cal.com's documented behavior
- Schema correctly validates the OAuth 2.0 refresh token response format
34-44: LGTM!Well-designed custom error class with proper Error extension and useful properties for debugging and error handling.
177-186: LGTM!Comprehensive error handling that properly preserves custom errors and wraps unexpected exceptions with appropriate context.
240-244: No issues found with the token expiry handling.The code correctly defaults to
isExpired = falsewhenaccessTokenExpiresAtis null. This is safe and by design:
- Initial OAuth tokens don't have
accessTokenExpiresAtset (betterAuth doesn't compute it at creation time)- These tokens are used as-is on first call
- Upon refresh (triggered either manually or after an API failure),
accessTokenExpiresAtis set using theexpires_invalue from Cal.com- Future token checks then benefit from the 5-minute proactive refresh buffer
- The reactive pattern is acceptable and avoids unnecessary token refreshes
README.md (1)
52-60: LGTM!Clear and accurate documentation of the automatic token refresh feature. The explanation is user-friendly and correctly references the implementation details.
| const clientId = process.env.CAL_COM_CLIENT_ID; | ||
| const clientSecret = process.env.CAL_COM_CLIENT_SECRET; | ||
|
|
||
| if (!clientId || !clientSecret) { | ||
| throw new TokenRefreshError( | ||
| "Cal.com OAuth credentials not configured", | ||
| 500 | ||
| ); | ||
| } |
There was a problem hiding this comment.
Critical: Environment variable name mismatch.
The code references CAL_COM_CLIENT_ID and CAL_COM_CLIENT_SECRET, but the README.md (lines 39-40) documents the environment variables as CAL_OAUTH_CLIENT_ID and CAL_OAUTH_CLIENT_SECRET. This mismatch will cause the refresh flow to always fail with "Cal.com OAuth credentials not configured".
Apply this diff to use the documented variable names:
- const clientId = process.env.CAL_COM_CLIENT_ID;
- const clientSecret = process.env.CAL_COM_CLIENT_SECRET;
+ const clientId = process.env.CAL_OAUTH_CLIENT_ID;
+ const clientSecret = process.env.CAL_OAUTH_CLIENT_SECRET;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const clientId = process.env.CAL_COM_CLIENT_ID; | |
| const clientSecret = process.env.CAL_COM_CLIENT_SECRET; | |
| if (!clientId || !clientSecret) { | |
| throw new TokenRefreshError( | |
| "Cal.com OAuth credentials not configured", | |
| 500 | |
| ); | |
| } | |
| const clientId = process.env.CAL_OAUTH_CLIENT_ID; | |
| const clientSecret = process.env.CAL_OAUTH_CLIENT_SECRET; | |
| if (!clientId || !clientSecret) { | |
| throw new TokenRefreshError( | |
| "Cal.com OAuth credentials not configured", | |
| 500 | |
| ); | |
| } |
🤖 Prompt for AI Agents
In lib/auth/refresh-token.ts around lines 110 to 118, the code reads
process.env.CAL_COM_CLIENT_ID and process.env.CAL_COM_CLIENT_SECRET but the
README documents CAL_OAUTH_CLIENT_ID and CAL_OAUTH_CLIENT_SECRET; replace the
environment variable names to process.env.CAL_OAUTH_CLIENT_ID and
process.env.CAL_OAUTH_CLIENT_SECRET so the refresh flow finds the correct
credentials, and scan/update any other occurrences in the repo to keep names
consistent.
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
echo "=== Checking README.md for environment variable documentation ==="
cat README.md | grep -A5 -B5 "CLIENT_ID\|CLIENT_SECRET"
echo -e "\n=== Searching for CAL_COM_CLIENT_ID usage in codebase ==="
rg -n "CAL_COM_CLIENT_ID" --type-add 'env:.env*' --type env
echo -e "\n=== Searching for CAL_COM_CLIENT_ID in TypeScript files ==="
rg -n "CAL_COM_CLIENT_ID" --type ts
echo -e "\n=== Searching for CAL_OAUTH_CLIENT_ID usage in codebase ==="
rg -n "CAL_OAUTH_CLIENT_ID" --type-add 'env:.env*' --type env
echo -e "\n=== Searching for CAL_OAUTH_CLIENT_ID in TypeScript files ==="
rg -n "CAL_OAUTH_CLIENT_ID" --type ts
echo -e "\n=== Checking for .env files ==="
fd -t f ".env" --no-ignore
echo -e "\n=== Checking .env.example or .env.local.example if exists ==="
cat .env.example 2>/dev/null || echo ".env.example not found"
cat .env.local.example 2>/dev/null || echo ".env.local.example not found"
Length of output: 1733
@zhyd1997, you're absolutely right—I apologize for the confusion!
After verifying, the code correctly uses CAL_COM_CLIENT_ID and CAL_COM_CLIENT_SECRET, which matches both your .env.example and the existing lib/auth.ts file.
The actual inconsistency is in the README.md documentation, which lists the variables as CAL_OAUTH_CLIENT_ID and CAL_OAUTH_CLIENT_SECRET, while the codebase uses CAL_COM_CLIENT_ID and CAL_COM_CLIENT_SECRET.
You might want to update the README.md table (lines 39-40) to match the actual variable names:
-| `CAL_OAUTH_CLIENT_ID` | Yes | OAuth client ID from your Cal.com developer app | – |
-| `CAL_OAUTH_CLIENT_SECRET` | Yes | OAuth client secret from Cal.com | – |
+| `CAL_COM_CLIENT_ID` | Yes | OAuth client ID from your Cal.com developer app | – |
+| `CAL_COM_CLIENT_SECRET` | Yes | OAuth client secret from Cal.com | – |Sorry for the false alarm on this one!
🐰💭
((
(-.-)
o_(")(")
There was a problem hiding this comment.
Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!
Auto Refresh Access Token Support
Adding automatic refresh token support for Cal.com OAuth integration.
Changes:
CAL_REFRESH_TOKEN_URLconstantlib/auth/refresh-token.tsImplementation:
Token Refresh Utilities (
lib/auth/refresh-token.ts):getValidAccessToken(userId): Returns valid token, auto-refreshing when expired or within 5min of expiryrefreshCalAccessToken(userId): Calls Cal.com's refresh endpoint with Zod validationTokenRefreshError: Custom error class with status codesexpires_inServer Action Integration (
app/(dashboard)/bookings/actions.ts):getValidAccessToken()for transparent token refreshConstants (
constants/oauth.ts):CAL_REFRESH_TOKEN_URLconstantHow It Works:
getValidAccessToken(userId)expires_innot provided)Code Quality:
Original prompt
access_tokensupport #54✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.
Summary by CodeRabbit
New Features
Documentation