Social media access tokens: long-lived, refresh, and why they keep expiring
Your Instagram access token expires because Meta issues it for 60 days and only extends it if you ask. Facebook, LinkedIn, TikTok, X and YouTube each run a different clock and a different refresh call. Here are the real lifetimes, read on each platform's own documentation on October 12, 2026, with the refresh request for each one.
What an Instagram access token actually is
There is no single Instagram token. There are two paths, and they expire differently.
With Instagram API with Instagram Login, your app sends the user to Instagram, gets an authorization code back, and exchanges it. Meta's business login documentation sets the rules: the authorization code is valid for one hour and single use, you POST it to https://api.instagram.com/oauth/access_token with grant_type=authorization_code, and you get a short-lived token. That short-lived token is not what you store. You exchange it server side:
curl -s -G https://graph.instagram.com/access_token \
-d grant_type=ig_exchange_token \
-d client_secret=$IG_APP_SECRET \
-d access_token=$SHORT_LIVED_TOKEN
The response carries expires_in: 5183944, which is 60 days minus a few minutes. That is your long-lived token.
With Instagram API with Facebook Login, the account is linked to a Facebook Page and you work with a Page access token instead. Same posting endpoints, different token, different expiry rules. Pick one path per app.
Long lived access token on Instagram: the 60-day clock and the 24-hour rule
A long-lived Instagram token is not permanent. It is renewable, which is a different promise. You renew it with one GET:
curl -s -G https://graph.instagram.com/refresh_access_token \
-d grant_type=ig_refresh_token \
-d access_token=$LONG_LIVED_TOKEN
Three conditions apply, and all three come from the same Meta page:
- The token must be at least 24 hours old. Refreshing right after the exchange fails.
- The token must not already be expired. Meta is explicit: a token that goes 60 days without a refresh "can no longer be refreshed."
- The user must still have granted
instagram_business_basic.
Condition 2 is where accounts die. There is no grace period and no recovery call. Once the 60 days are gone, the only way back is the full login flow, which means the human has to click again. So the refresh job is not a nice-to-have, it is the thing that keeps the integration alive. I run it on a cadence of days, not weeks: a daily pass that refreshes anything older than 30 days leaves you 30 days of margin for a broken cron, a bad deploy or a holiday.
Facebook page access token: the one that behaves differently
A Facebook Page token is derived, not issued directly. You log the admin in, you get a user token, and you call the Graph API for the Page token. Meta's access token guide gives the user side in plain numbers: short-lived user tokens "typically last about one to two hours", long-lived user tokens "last about 60 days", and apps with Standard access to the Marketing API or System User tokens get tokens that "do not expire based on time".
For the Page token itself, that same guide states no lifetime. It says a Page token is "unique to each Page, admin, and app combination" and points you at the Access Token Tool and the expiration documentation. So do not hardcode an assumption. Read expires_at in the debugger for your own app and store it: the behaviour depends on which token you derived it from. The repeated claim that Page tokens never expire holds for some derivations only, and Meta warns against depending on any published lifetime.
Token lifetimes across six platforms
Every figure below is from the platform's own developer documentation, read on October 12, 2026. Where a page publishes no number, the cell says so rather than guessing.
| Platform | Access token life | Refresh credential | Refresh endpoint | The gotcha |
|---|---|---|---|---|
| Instagram (Instagram Login) | 60 days | The token itself | graph.instagram.com/refresh_access_token |
Must be 24h old, dead at 60 days |
| Facebook (user) | 1 to 2 hours, then about 60 days | Exchange with app secret | graph.facebook.com/oauth/access_token |
Page token lifetime not published |
| 60 days | Refresh token, 365 days | linkedin.com/oauth/v2/accessToken |
Programmatic refresh is for approved MDP partners only | |
| TikTok | 24 hours | Refresh token, 365 days | open.tiktokapis.com/v2/oauth/token/ |
A new refresh_token can come back, you must store it |
| X | Not published on the token page | Refresh token, needs offline.access |
api.x.com/2/oauth2/token |
No offline.access scope, no refresh, ever |
| YouTube (Google) | 1 hour | Refresh token, no fixed expiry | oauth2.googleapis.com/token |
Dies after 6 months unused, 7 days if your app is in Testing |
Two rows deserve more than a cell.
LinkedIn's refresh token page says programmatic refresh is available "for all approved Marketing Developer Platform (MDP) partners". If your app is not one, you get a 60-day access token and no refresh token, and the member reauthorizes by hand. The refresh token's own clock does not reset either: LinkedIn's example walks through day 1 at 365 days, day 59 at 306 days, day 360 at 5 days left. Refreshing buys you a new access token, never a new year.
Google's OAuth 2.0 page lists the ways a refresh token stops working, and the one that bites small projects is publishing status: an external app still in Testing gets refresh tokens "expiring in 7 days". There is also a cap of 100 refresh tokens per Google Account per client ID, and creating the 101st silently invalidates the oldest. If you mint a token per run instead of reusing one, you will hit that.
Refresh access token on a social API: the pattern that works
The calls differ, the shape does not. Four rules carry across all six platforms.
Store the expiry, not just the token. A row with access_token, refresh_token, expires_at and refresh_expires_at lets a single cron job ask one question: what expires in the next 7 days? Without expires_at you are reduced to waiting for a 401.
Refresh early and on a schedule. Refresh-on-401 fails on the one platform where it cannot work: Instagram, where an expired token is unrecoverable. Instagram's 24-hour minimum age also means you cannot refresh on demand at any moment.
Always write back what comes back. TikTok's refresh response can return a new refresh_token with a new refresh_expires_in, and TikTok's token management doc says to use the new value if it changed. An integration that keeps replaying the original refresh token works until it does not.
Treat reconnection as a product feature, not an error path. Tokens get revoked when the user changes a password with Gmail scopes attached, removes your app, or leaves the company whose Page they administered. The question is not whether you avoid that, it is how fast the account owner finds out. X's token documentation is the reminder that this starts at authorization time: no offline.access in the original scopes and no refresh token is ever issued, so the only fix is a new consent screen.
What I do instead
I stopped writing this layer. PlugKit connects accounts with one call, GET /connect/{platform}?profileId=…, returns an authUrl you open, and stores and refreshes the tokens itself. The profiles and accounts documentation is explicit that account responses expose platform, username, status and profileId and never the access token, which is the point: there is no token in my database to leak or forget to renew.
What matters more than the refresh is the failure signal. PlugKit's webhook list includes account.disconnected, which fires when an account is disconnected or its token stops working. That is the event you actually need, because every design above still ends the same way: a human has to click once in a while, and your job is to ask them the same day rather than three weeks later when the posts quietly stopped.
Where PlugKit is not the answer: if you run one account on one platform, the refresh job above is 40 lines and you do not need us. If you need a platform we do not support, you are writing the OAuth flow anyway. And the pass-through costs are real: X API calls are billed at cost, $0.005 per read and $0.015 per publish, on top of the plan.
For what sits on top of these tokens, read the 2026 social media API guide and the Instagram Graph API guide. The rate limits table is the other half of the problem. If an agent does the posting, MCP or REST API for your agent is the decision before this one.
PlugKit is $49 a month for 5 connected accounts, cancel anytime, or $97 for 30. The trial is 7 days free, no card, with one connected account, and the clock starts when you connect that account.
FAQ
Why does my Instagram access token keep expiring?
Because a long-lived Instagram token lasts 60 days and is renewable rather than permanent. You have to call refresh_access_token with grant_type=ig_refresh_token before those 60 days run out. The token also has to be at least 24 hours old to be refreshed, and once it expires Meta's documentation says it can no longer be refreshed, so the user must log in again.
How long does a long lived access token last on Instagram?
60 days. The exchange response returns expires_in: 5183944 seconds, and each successful refresh gives you another 60 days from that moment.
Does a Facebook page access token expire?
Meta's Facebook Login access token guide does not publish a lifetime for Page tokens. It confirms 1 to 2 hours for short-lived user tokens and about 60 days for long-lived ones, and tells you to check Page and app tokens in the Access Token Tool. Read expires_at for your own app instead of trusting a blog post, including this one.
Can I refresh a token on every social API?
No. TikTok, LinkedIn, Google and X all use refresh tokens, but LinkedIn restricts programmatic refresh to approved Marketing Developer Platform partners, and X issues a refresh token only if the original authorization requested the offline.access scope. Where refresh is unavailable, the only path is a new authorization by the account owner.
What happens to scheduled posts when a token dies?
They fail at publish time, usually with a 401 from the platform, and on most stacks nothing tells the user. Subscribe to a disconnection event and alert the account owner the same day. PlugKit sends account.disconnected when an account is disconnected or its token stops working.
One plug for every platform your agent touches
$49 a month for 5 connected accounts, cancel anytime. Every feature in every plan.
Get your API key →