@@ -8,6 +8,7 @@ import { withLeaderLock } from '@/lib/concurrency/leader-lock'
88import { coalesceLocally } from '@/lib/concurrency/singleflight'
99import { decryptSecret } from '@/lib/core/security/encryption'
1010import { refreshOAuthToken } from '@/lib/oauth'
11+ import { isInstagramProvider , shouldProactivelyRefreshInstagramToken } from '@/lib/oauth/instagram'
1112import {
1213 getMicrosoftRefreshTokenExpiry ,
1314 isMicrosoftProvider ,
@@ -450,6 +451,7 @@ export async function getOAuthToken(userId: string, providerId: string): Promise
450451 accessTokenExpiresAt : account . accessTokenExpiresAt ,
451452 idToken : account . idToken ,
452453 scope : account . scope ,
454+ updatedAt : account . updatedAt ,
453455 } )
454456 . from ( account )
455457 . where ( and ( eq ( account . userId , userId ) , eq ( account . providerId , providerId ) ) )
@@ -463,19 +465,33 @@ export async function getOAuthToken(userId: string, providerId: string): Promise
463465
464466 const credential = connections [ 0 ]
465467
466- // Determine whether we should refresh: missing token OR expired token
468+ // Determine whether we should refresh: missing/expired token, or Instagram
469+ // long-lived token nearing expiry (Meta cannot refresh after expiry).
467470 const now = new Date ( )
468471 const tokenExpiry = credential . accessTokenExpiresAt
469- const shouldAttemptRefresh =
472+ const accessTokenNeedsRefresh =
470473 ! ! credential . refreshToken && ( ! credential . accessToken || ( tokenExpiry && tokenExpiry < now ) )
474+ const instagramNeedsProactiveRefresh =
475+ ! ! credential . refreshToken &&
476+ isInstagramProvider ( providerId ) &&
477+ shouldProactivelyRefreshInstagramToken ( {
478+ accessTokenExpiresAt : credential . accessTokenExpiresAt ,
479+ updatedAt : credential . updatedAt ,
480+ now,
481+ } )
471482
472- if ( shouldAttemptRefresh ) {
473- return performCoalescedRefresh ( {
483+ if ( accessTokenNeedsRefresh || instagramNeedsProactiveRefresh ) {
484+ const fresh = await performCoalescedRefresh ( {
474485 accountId : credential . id ,
475486 providerId,
476487 refreshToken : credential . refreshToken ! ,
477488 userId,
478489 } )
490+ if ( fresh ) return fresh
491+ if ( ! accessTokenNeedsRefresh && credential . accessToken ) {
492+ return credential . accessToken
493+ }
494+ return null
479495 }
480496
481497 if ( ! credential . accessToken ) {
@@ -550,7 +566,18 @@ export async function refreshAccessTokenIfNeeded(
550566 refreshTokenExpiresAt &&
551567 refreshTokenExpiresAt <= proactiveRefreshThreshold
552568
553- const shouldRefresh = accessTokenNeedsRefresh || refreshTokenNeedsProactiveRefresh
569+ // Instagram long-lived tokens can only be refreshed while still valid.
570+ const instagramNeedsProactiveRefresh =
571+ ! ! credential . refreshToken &&
572+ isInstagramProvider ( credential . providerId ) &&
573+ shouldProactivelyRefreshInstagramToken ( {
574+ accessTokenExpiresAt,
575+ updatedAt : credential . updatedAt ,
576+ now,
577+ } )
578+
579+ const shouldRefresh =
580+ accessTokenNeedsRefresh || refreshTokenNeedsProactiveRefresh || instagramNeedsProactiveRefresh
554581
555582 const accessToken = credential . accessToken
556583
@@ -567,8 +594,8 @@ export async function refreshAccessTokenIfNeeded(
567594 } )
568595 if ( fresh ) return fresh
569596
570- // If refresh was only triggered proactively (Microsoft refresh-token aging),
571- // the still-valid access token is a fine fallback .
597+ // If refresh was only triggered proactively (Microsoft refresh-token aging /
598+ // Instagram long-lived nearing expiry), the still-valid access token is fine.
572599 if ( ! accessTokenNeedsRefresh && accessToken ) {
573600 logger . info ( `[${ requestId } ] Refresh unavailable; reusing still-valid access token` )
574601 return accessToken
@@ -616,7 +643,18 @@ export async function refreshTokenIfNeeded(
616643 refreshTokenExpiresAt &&
617644 refreshTokenExpiresAt <= proactiveRefreshThreshold
618645
619- const shouldRefresh = accessTokenNeedsRefresh || refreshTokenNeedsProactiveRefresh
646+ // Instagram long-lived tokens can only be refreshed while still valid.
647+ const instagramNeedsProactiveRefresh =
648+ ! ! credential . refreshToken &&
649+ isInstagramProvider ( credential . providerId ) &&
650+ shouldProactivelyRefreshInstagramToken ( {
651+ accessTokenExpiresAt,
652+ updatedAt : credential . updatedAt ,
653+ now,
654+ } )
655+
656+ const shouldRefresh =
657+ accessTokenNeedsRefresh || refreshTokenNeedsProactiveRefresh || instagramNeedsProactiveRefresh
620658
621659 // If token appears valid and present, return it directly
622660 if ( ! shouldRefresh ) {
0 commit comments