Every social platform has its own OAuth implementation, and they agree on roughly the shape and nothing else. This is what you’re signing up for, and what you can skip.
What differs per platform
Scopes. Different names, different granularity, different requirements. Asking for too many gets your app rejected in review. Asking for too few means a feature silently doesn’t work.
Token lifetime. Some tokens last a long time. Some expire in weeks. Some can be exchanged for longer-lived ones through a separate call you have to know about.
Refresh behaviour. Some issue refresh tokens, some require re-authorisation, some rotate the refresh token each time so storing the old one breaks the next refresh.
Review. Several platforms won’t grant publishing scopes until they’ve reviewed your app, which can involve a privacy policy, a demo video and a wait. That’s calendar time you don’t control, and it can be refused.
The account model. A personal profile, a page, a business account and a channel are different objects with different permissions. Getting a token isn’t the same as knowing which account you can actually post to.
The part that actually breaks: refresh
Not the initial flow. The initial flow is a day of work and then it’s done.
What breaks in production is refresh, and it breaks quietly:
- A token expires and the refresh job failed three days ago
- Nothing errors visibly, because nothing tried to publish until now
- A scheduled post fails
- The user finds out before you do
Any real implementation needs a scheduled refresh job, monitoring for refresh failures, a way to mark a connection as broken, and a reconnection prompt in your UI. That’s more work than the OAuth flow itself and it’s the part estimates leave out.
If you build it yourself
Things worth doing from the start:
Store tokens encrypted, and never log them. They’re credentials to someone else’s account.
Store the expiry and refresh ahead of it, not on failure.
Handle rotation. If a platform rotates refresh tokens, write the new one before you use it, not after.
Model a broken connection as a real state. Not an error you catch, a state a user can see and fix.
Expect re-authorisation. Permission changes and policy updates mean users will occasionally need to reconnect regardless of what you do.
Avoiding most of it
If publishing is a feature of your product rather than the product, the alternative is one integration where the platform OAuth is somebody else’s problem.
Two auth models, and picking the right one matters:
API key, for acting on your own account. Server-to-server, no user consent flow, simplest thing that works.
OAuth, for acting on behalf of your users. They approve your app and you get a scoped token bound to the workspace they chose, rather than asking them to paste a credential into your product.
If your product is multi-user, use OAuth from the start. Asking users to paste an API key is a migration you’ll have to do later, and it teaches them a habit you don’t want.
How BulkPublish’s OAuth works
- Authorization endpoint:
https://app.bulkpublish.com/oauth/authorize - Token endpoint:
https://app.bulkpublish.com/api/oauth/token - PKCE (S256) required for every client
scopeis required, with no implicit default- Authorization codes are single-use and refresh tokens rotate
- Tokens are passed as
Bearer bpat_...
Scopes are granular: posts:read, posts:write, media:read, media:write, analytics:read, channels:read, or full.
One deliberate boundary worth knowing: OAuth tokens reach posts, schedules, labels, media, analytics, quota usage and read-only channel data, and nothing else. Account administration, meaning team, organizations, billing, credit purchases, API keys and OAuth app management, returns 403 for any OAuth token including full. Those actions would outlive a user disconnecting your app, so they require an API key instead.
That’s the sort of limit worth designing around early rather than discovering when a 403 appears in production.
The short version
The OAuth flow is a day per platform. Token refresh is forever, and it fails silently, which is why it’s the part that actually hurts. If publishing is a feature rather than your product, one integration with a provider removes fifteen of these. Use OAuth rather than pasted API keys the moment other people’s accounts are involved.