Skip to content

fix: update encryptedKey alongside key on OAuth token refresh#28460

Draft
volnei wants to merge 1 commit intomainfrom
devin/1773711246-fix-encrypted-key-token-refresh
Draft

fix: update encryptedKey alongside key on OAuth token refresh#28460
volnei wants to merge 1 commit intomainfrom
devin/1773711246-fix-encrypted-key-token-refresh

Conversation

@volnei
Copy link
Contributor

@volnei volnei commented Mar 17, 2026

What does this PR do?

When OAuth tokens are refreshed, updateTokenObjectInDb updates the key column but never updates encryptedKey. Since getCalendarsEvents always prefers encryptedKey over key when it exists, subsequent requests decrypt the stale encrypted token (with the original expiry_date), see it as expired, and trigger another Google /token call — on every single request.

This PR re-encrypts the refreshed token and persists it to encryptedKey alongside key, using the same encryptSecret pattern as initial credential creation.

Changes:

  • updateTokenObject.ts — added tryEncryptTokenObject helper; spreads encryptedKey into all three DB write paths (delegation update, delegation create, direct credential update). Added required credentialType param to the oauth strategy branch.
  • CredentialRepository.ts — widened updateWhereId and updateWhereUserIdAndDelegationCredentialId signatures to accept optional encryptedKey.
  • CrmService.ts (Pipedrive) — passes credentialType to satisfy the updated signature.

⚠️ Key review items

  1. Missing caller? — Verify that the Google Calendar path (CalendarAuth.tsOAuthManagerupdateTokenObjectInDb) also passes credentialType after this change. This is the primary path that triggered the bug. If the intermediate callback wiring doesn't forward credentialType, the encryption won't happen for Google Calendar credentials specifically.
  2. createDelegationCredential — The JWT fallback path (line 84) spreads encryptedKey into createDelegationCredential. Confirm that method's Prisma create call accepts encryptedKey in its data.
  3. Encryption failure fallbacktryEncryptTokenObject returns undefined on error (silently skips encryptedKey update). This means the stale-token problem persists if encryption breaks, but key is still updated so the system degrades gracefully.

Mandatory Tasks (DO NOT REMOVE)

  • I have self-reviewed the code (A decent size PR without self-review might be rejected).
  • I have updated the developer docs in /docs if this PR makes changes that would require a documentation change. N/A — no docs changes needed.
  • I confirm automated tests are in place that prove my fix is effective or that my feature works.

How should this be tested?

  1. Set up a Cal.com instance with the CREDENTIALS encryption keyring configured
  2. Connect a Google Calendar credential (creates both key and encryptedKey)
  3. Wait for the token's expiry_date to pass (or manually set it to the past in the DB)
  4. Hit the getSchedule or calendarOverlay endpoint multiple times with >2s gaps
  5. Before fix: each request triggers a Google /token call
  6. After fix: only the first request refreshes; subsequent requests reuse the persisted token

Alternatively, inspect the Credential table after a token refresh and confirm encryptedKey was updated (decrypt it and check expiry_date matches the fresh token).

Checklist

  • My code follows the style guidelines of this project
  • I have commented my code, particularly in hard-to-understand areas
  • My changes generate no new warnings

Link to Devin session: https://app.devin.ai/sessions/d8775f5ea1d6469c9853ca400e8cf286
Requested by: @volnei

When a token is refreshed, updateTokenObjectInDb only updated the
key column in the database. If the credential also had encryptedKey
set (which happens when the CREDENTIALS keyring is configured),
subsequent requests would decrypt the stale encryptedKey and see an
expired token, triggering a redundant Google /token call on every
request.

Now updateTokenObjectInDb re-encrypts the refreshed token and
persists it to encryptedKey as well, so the next request reads the
fresh token and skips the unnecessary refresh.

Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com>
@devin-ai-integration
Copy link
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR that start with 'DevinAI' or '@devin'.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 3 files

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant