Centralize the Meta long-lived token TTL and clarify the extension helper

The 60-day fallback used when Meta omits expires_in was duplicated as a bare
5184000 across the Instagram/Threads connect and refresh code; it now lives in
one place, Platform::LONG_LIVED_TOKEN_TTL_SECONDS. Also renames
Platform::extensionModelValues() to accessTokenExtendingPlatformValues() so the
name states what it returns without needing the extendsAccessTokenOnRefresh
docblock.
This commit is contained in:
Paulo Castellano 2026-07-03 11:07:54 -03:00
parent 545a779848
commit 4d5ca6b274
4 changed files with 16 additions and 9 deletions

View file

@ -32,10 +32,10 @@ public function handle(): void
->whereNotNull('token_expires_at')
->where(function (Builder $query) {
$query->where(function (Builder $extension) {
$extension->whereIn('platform', Platform::extensionModelValues())
$extension->whereIn('platform', Platform::accessTokenExtendingPlatformValues())
->where('token_expires_at', '<=', now()->addDay());
})->orWhere(function (Builder $rotating) {
$rotating->whereNotIn('platform', Platform::extensionModelValues())
$rotating->whereNotIn('platform', Platform::accessTokenExtendingPlatformValues())
->where('token_expires_at', '<=', now()->addMinutes(30));
});
})

View file

@ -23,6 +23,13 @@ enum Platform: string
case Telegram = 'telegram';
case Discord = 'discord';
/**
* Fallback lifetime, in seconds, for Meta long-lived tokens (Instagram and
* Threads — see extendsAccessTokenOnRefresh) when the provider response
* omits expires_in. Meta issues these tokens for 60 days.
*/
public const LONG_LIVED_TOKEN_TTL_SECONDS = 5184000;
/**
* The social network this platform belongs to. Variants that represent the
* same network (LinkedIn profile vs. company page, Instagram standalone vs.
@ -278,14 +285,14 @@ public function extendsAccessTokenOnRefresh(): bool
}
/**
* All platform values that refresh by extending the access_token itself
* (see extendsAccessTokenOnRefresh). Because these can't be refreshed once
* expired, the proactive-refresh cron gives them a wider window than
* rotating platforms so a queue backlog can't let them lapse.
* The `platform` column values of the platforms that refresh by extending
* their access token in place (Instagram and Threads — see
* extendsAccessTokenOnRefresh), for use in database whereIn/whereNotIn
* filters. Derived from extendsAccessTokenOnRefresh() so the two never drift.
*
* @return array<int, string>
*/
public static function extensionModelValues(): array
public static function accessTokenExtendingPlatformValues(): array
{
return array_values(array_map(
fn (self $platform): string => $platform->value,

View file

@ -69,7 +69,7 @@ public function callback(Request $request): InertiaResponse
$avatarPath = $socialUser->getAvatar() ? uploadFromUrl($socialUser->getAvatar()) : null;
// Calculate token expiration (long-lived tokens last 60 days)
$expiresIn = $socialUser->expiresIn ?? 5184000; // 60 days in seconds
$expiresIn = $socialUser->expiresIn ?? SocialPlatform::LONG_LIVED_TOKEN_TTL_SECONDS;
$tokenExpiresAt = now()->addSeconds($expiresIn);
$workspace->socialAccounts()->updateOrCreate(

View file

@ -116,7 +116,7 @@ public function callback(Request $request): InertiaResponse
$longLivedData = $longLivedResponse->json();
$longLivedToken = $longLivedData['access_token'] ?? $shortLivedToken;
$expiresIn = $longLivedData['expires_in'] ?? 5184000;
$expiresIn = $longLivedData['expires_in'] ?? SocialPlatform::LONG_LIVED_TOKEN_TTL_SECONDS;
// Fetch user profile
$profileResponse = Http::get(config('trypost.platforms.threads.graph_api')."/{$userId}", [