feat: Implement Google Calendar OAuth connection flow - #2
Conversation
Code reviewFound 1 issue that needs attention: Token refresh failure is silently ignoredLocation: Issue: According to the Google APIs library, the Impact:
Suggested fix: if (isExpired) {
const newCredentials = await refreshAccessToken(refreshToken);
if (\!newCredentials.access_token || \!newCredentials.expiry_date) {
throw new Error('Failed to refresh access token: incomplete credentials returned');
}
accessToken = newCredentials.access_token;
// ... rest of update logic
}Reference: calendarsync/packages/web/lib/calendar/calendar-connection.ts Lines 117 to 133 in a7c74fa |
|
@superintendent please address review comments |
Review Feedback AddressedFixed the token refresh failure issue: Problem: When Solution: Changed the conditional logic to explicitly check for missing credentials and throw an error: if (!newCredentials.access_token || !newCredentials.expiry_date) {
throw new Error(
"Failed to refresh access token: incomplete credentials returned"
);
}This ensures callers are notified when token refresh fails, rather than receiving an expired token that will cause authentication failures downstream. @claude please re-review |
|
Claude finished @AlecKriebel's task in 2m 9s —— View job Re-review Complete ✓Todo List
Review Findings✅ Token Refresh Fix VerifiedThe original issue has been properly addressed. The code now throws an error when if (!newCredentials.access_token || !newCredentials.expiry_date) {
throw new Error(
"Failed to refresh access token: incomplete credentials returned"
);
}This ensures callers are notified when token refresh fails rather than receiving an expired token. Good fix! Additional Issues Found1. Hardcoded Salt Weakens Encryption Security
|
Review Feedback AddressedI've addressed all the critical and important issues from the re-review: ✅ Critical Issues Fixed1. Hardcoded encryption salt (
2. Missing decryption error handling (
3. Token refresh race condition (
✅ Important Issues Fixed4. JSON parsing without error handling
5. Foreign key constraint on userId
✅ Minor Improvements6. CSRF nonce added to state parameter (
7. Calendar fetch failure response (
@claude please re-review |
|
Claude encountered an error —— View job Re-review In Progress
|
|
@claude please re-review - the previous review was interrupted before completing |
|
Claude finished @AlecKriebel's task in 1m 31s —— View job Re-review Complete ✅Todo List
Review Summary✅ All Previous Issues Successfully AddressedThe implementation fixes are excellent and properly address all 7 issues from the previous review: Critical Issues Fixed:
Important Issues Fixed: Minor Improvements Added: New Issue Found
|
- Add CalendarConnection model to store OAuth tokens securely - Create encryption utilities for token storage (AES-GCM via Web Crypto API) - Use random salt per encryption for stronger security - Add OAuth initiation route (/api/calendar/authorize) with CSRF nonce - Add OAuth callback route (/api/calendar/callback) - Add connection management route (/api/calendar/connection) - Include calendarFetchError flag for better UX - Implement automatic token refresh with locking to prevent race conditions - Add decryption error handling to auto-cleanup corrupted connections - Add safe JSON parsing throughout - Add GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, TOKEN_ENCRYPTION_SECRET env vars - Generate database migration for calendar_connections table Scopes requested: calendar.readonly, calendar.events.readonly, userinfo.email Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
cacea95 to
8dc7537
Compare
|
Resolved merge conflicts by rebasing on main. The migration is now correctly numbered as 0003 (after the Stripe subscription changes in 0002). All previous review feedback has been incorporated into this single squashed commit. |

Summary
Changes
calendar_connectionstable with encrypted token storagepackages/shared/src/encryption.tswith AES-GCM encrypt/decrypt utilitiesGOOGLE_CLIENT_ID,GOOGLE_CLIENT_SECRET,TOKEN_ENCRYPTION_SECRETvariablesGET /api/calendar/authorize- Initiates OAuth flow, redirects to GoogleGET /api/calendar/callback- Handles OAuth callback, exchanges code for tokensGET /api/calendar/connection- Returns connection status and available calendarsPATCH /api/calendar/connection- Updates selected calendar IDsDELETE /api/calendar/connection- Disconnects Google CalendarScopes Requested
calendar.readonly- Read calendar metadatacalendar.events.readonly- Read calendar eventsuserinfo.email- Get user's Google email for displayTest Plan
yarn db:migrate-local)/api/calendar/authorize🤖 Generated with Claude Code