BrandPilot — LinkedIn Token Expired
Trigger: LinkedIn posts fail to publish. Users see “LinkedIn token expired” or “LinkedIn authorization failed” error in the BrandPilot UI.
Data location: social_accounts table in Supabase — status, token_expires_at, access_token columns.
1. Confirm
Check affected accounts in Supabase
-- Run in Supabase SQL editor or via service role API:
SELECT id, user_id, provider, status, token_expires_at
FROM social_accounts
WHERE provider = 'linkedin'
AND (status = 'expired' OR token_expires_at < now())
ORDER BY token_expires_at ASC;If rows are returned → tokens are expired. Proceed below.
2. Root cause
LinkedIn OAuth tokens expire after 60 days (standard) or 2 hours (access token; refreshed via refresh token).
Possible causes:
- User’s access token expired and refresh failed (most common)
- Refresh token expired (60-day lifetime) — user must re-authorize
- LinkedIn app credentials changed (
LINKEDIN_CLIENT_ID/LINKEDIN_CLIENT_SECRET) — all tokens invalidated - LinkedIn app removed from our LinkedIn Developer account — all tokens invalidated
3. Fix
Fix A: User re-authorizes (most common fix)
Each affected user must reconnect their LinkedIn account:
- User navigates to Settings → Social Accounts in BrandPilot
- Clicks “Reconnect LinkedIn” next to the expired account
- Completes the LinkedIn OAuth flow
- The
/api/auth/linkedin/callbackroute handles token storage
No admin action needed — this is fully self-service.
To notify affected users (optional, admin):
- Query
social_accountsfor expired tokens, getuser_id, look up email inprofilestable - Send notification email via Resend:
POST /api/admin/notify-linkedin-reauth(if implemented)
Fix B: LinkedIn app credentials changed
If the LinkedIn Developer app’s Client ID or Client Secret was rotated:
- Update in SOPS:
sops -d C:\code_2026\p24-infra\secrets\brandpilot.env.sops > /tmp/brandpilot.env # Edit: update LINKEDIN_CLIENT_ID and LINKEDIN_CLIENT_SECRET sops -e /tmp/brandpilot.env > C:\code_2026\p24-infra\secrets\brandpilot.env.sops - Commit and push to a PR →
secrets-sync.ymlsyncs to Vercel on merge - Trigger Vercel redeployment
- All users must re-authorize LinkedIn (Fix A above)
Fix C: LinkedIn app suspended or removed
If the LinkedIn Developer app was suspended:
- Go to
https://developer.linkedin.com/→ sign in with admin account - Review app status — restore if suspended or recreate if deleted
- Update
LINKEDIN_CLIENT_ID,LINKEDIN_CLIENT_SECRET(Fix B above) - All users must re-authorize LinkedIn (Fix A above)
This is always a human action — apply human-action label to related issue.
4. LinkedIn OAuth re-auth flow (technical reference)
The re-auth flow entry point:
GET /api/auth/linkedin
└─ redirects to LinkedIn OAuth authorize URL with:
client_id=LINKEDIN_CLIENT_ID
scope=openid profile email w_member_social
redirect_uri=https://p24-brandpilot.zintegrowana.online/api/auth/linkedin/callback
state=<csrf-token>
GET /api/auth/linkedin/callback?code=...&state=...
└─ exchanges code for access_token + refresh_token
└─ upserts into social_accounts table:
{ provider: 'linkedin', access_token, refresh_token, token_expires_at, status: 'active' }
If callback returns an error, check Vercel runtime logs for the /api/auth/linkedin/callback function.
5. Escalate to human when
- LinkedIn app has been suspended or deleted → restore/recreate in LinkedIn Developer portal
- LinkedIn API rate limits hit → wait or contact LinkedIn support
- App credentials need rotation → SOPS update + Vercel re-sync (partially automated via
secrets-sync.yml)
6. Verify fix
After user re-authorizes, trigger a test LinkedIn post from the BrandPilot UI.
Also verify status = 'active' and token_expires_at > now() + interval '1 day' in social_accounts.