OAuth credential sync and app integration enhancements#4
Conversation
…11059) * Add credential sync .env variables * Add webhook to send app credentials * Upsert credentials when webhook called * Refresh oauth token from a specific endpoint * Pass appSlug * Add credential encryption * Move oauth helps into a folder * Create parse token response wrapper * Add OAuth helpers to apps * Clean up * Refactor `appDirName` to `appSlug` * Address feedback * Change to safe parse * Remove console.log --------- Co-authored-by: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Co-authored-by: Omar López <zomars@me.com>
Codoki PR ReviewSummary: Consolidate OAuth helpers, standardize refresh handling This review covered the top 30 of 40 files (risk-ranked). For complete coverage and faster feedback, consider splitting into ~1 smaller PR(s). Issues (Critical & High only)
Showing top 5 issues. Critical: 2, High: 3. See inline suggestions for more. Key Feedback (click to expand)
Confidence: 1/5 — Unsafe to merge (2 critical · 3 high · status: Requires changes · scope: top 30/40 files reviewed) React with 👍 or 👎 if you found this review useful. |
| } | ||
|
|
||
| if (!refreshTokenResponse.data.refresh_token) { | ||
| refreshTokenResponse.data.refresh_token = "refresh_token"; |
There was a problem hiding this comment.
🛑 Critical: Overwriting a missing refresh_token with the literal string "refresh_token" corrupts stored credentials; when an endpoint omits refresh_token (e.g., Office365), subsequent refreshes will fail after this default is saved. Instead, do not set a placeholder here—let callers preserve the existing refresh_token when absent.
| refreshTokenResponse.data.refresh_token = "refresh_token"; | |
| // preserve existing refresh_token at the callsite; do not override missing values here |
| const accessTokenParsed = parseRefreshTokenResponse(accessTokenJson, salesforceTokenSchema); | ||
|
|
||
| if (!accessTokenParsed.success) { | ||
| return Promise.reject(new Error("Invalid refreshed tokens were returned")); |
There was a problem hiding this comment.
🛑 Critical: Two issues: (1) prisma is used but not imported in this file, causing a runtime ReferenceError; (2) after refreshing tokens, the jsforce.Connection is constructed using credentialKey.instance_url and credentialKey.access_token (old values), not the freshly parsed tokens, so the connection may be initialized with an expired token. Import prisma from "@calcom/prisma" and use accessTokenParsed.data.instance_url and accessTokenParsed.data.access_token when creating the connection. Also prefer checking response.ok instead of response.statusText.
| } | ||
|
|
||
| // Decrypt the keys | ||
| const keys = JSON.parse( |
There was a problem hiding this comment.
| const keys = JSON.parse( | |
| let keys; | |
| try { | |
| const decrypted = symmetricDecrypt(reqBody.keys, process.env.CALCOM_APP_CREDENTIAL_ENCRYPTION_KEY || ""); | |
| keys = JSON.parse(decrypted); | |
| if (!keys || typeof keys !== "object") return res.status(400).json({ message: "Invalid keys payload" }); | |
| } catch (e) { | |
| return res.status(400).json({ message: "Invalid encrypted keys" }); | |
| } |
| "google-calendar", | ||
| credential.userId | ||
| ); | ||
| const token = res?.data; |
There was a problem hiding this comment.
| const token = res?.data; | |
| const token = res?.data; | |
| if (!token || !token.access_token || typeof token.expiry_date !== "number") { | |
| throw new Error("Failed to refresh Google access token: missing access_token/expiry_date"); | |
| } |
No description provided.