OAuth Delegation API

Verify social media account ownership in one integration

Let users connect their TikTok, Instagram, X (Twitter), LinkedIn, YouTube, Facebook, Pinterest or Threads account through PostSyncer, and receive back a cryptographically signed proof that they really own it. No per-platform OAuth to build, register or maintain.

HMAC-SHA256 signed No accounts stored Secret never in the browser
create-delegation-session.sh
# 1. Your server creates a session (api_key stays server-side)
curl -X POST https://postsyncer.com/api/oauth/delegate/sessions \
  -H "Authorization: Bearer $POSTSYNCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "platform": "tiktok",
       "callback_url": "https://yourapp.com/cb",
       "state": "a1b2c3" }'

# → opaque, single-use URL for the browser
{ "authorize_url": "https://app.postsyncer.com/oauth/delegate?request=psd_…",
  "expires_in": 900 }

Verify ownership on every platform PostSyncer supports

TikTok Instagram X (Twitter) LinkedIn YouTube Facebook Pinterest Threads

Stop building OAuth for every platform

Proving that a user owns a social account usually means registering a developer app with every network, getting through each app review, and maintaining token refreshes, scopes and breaking changes forever - per platform.

PostSyncer already does all of that. With OAuth delegation you reuse it: send the user through PostSyncer once and receive the platform's permanent user id plus a signature you verify with a shared secret. Learn more about our social media API and MCP tools.

  • One integration covers every supported platform
  • Tamper-proof HMAC-SHA256 ownership proof
  • No social accounts or tokens stored on your side
  • Built-in CSRF (state) and a 5-minute proof expiry
  • Returns the platform's permanent, spoof-proof user id

How OAuth delegation works

Four steps from your app to a verified, signed proof of ownership.

1

Create a session

Your server calls /oauth/delegate/sessions with your API key in the header. You get back an opaque, single-use authorize URL.

2

Authorize

Redirect the user to that URL. PostSyncer runs the platform's normal OAuth consent flow - your API key never touches the browser.

3

Receive proof

We redirect back to your callback with platform_id, handle, expires and a signed sig.

4

Verify

Check the state, confirm it hasn't expired, and verify the signature with your signing secret. Then trust platform_id as proof.

Quickstart

Create a session on your server, send the user to authorize, then verify the signed callback. Pick your language:

// 1) Create a delegation session (server-side)
const r = await fetch("https://postsyncer.com/api/oauth/delegate/sessions", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.POSTSYNCER_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    platform: "tiktok",
    callback_url: "https://yourapp.com/postsyncer/callback",
    state,            // random, persisted, single-use
  }),
});
const { authorize_url } = await r.json();
res.redirect(authorize_url);   // 2) send the user to authorize

// 3) verify the signed callback PostSyncer redirects back to
import crypto from "crypto";
function verify(q, secret, expectedState) {
  if (q.state !== expectedState) return false;            // CSRF
  if (Number(q.expires) < Date.now() / 1000) return false; // fresh
  const base =
    `platform=${q.platform}&platform_id=${q.platform_id}` +
    `&handle=${q.handle}&state=${q.state}&expires=${q.expires}`;
  const expected = crypto.createHmac("sha256", secret).update(base).digest("hex");
  return crypto.timingSafeEqual(Buffer.from(q.sig), Buffer.from(expected));
}
# 1) Create a delegation session (server-side)
import requests, hmac, hashlib, time

r = requests.post(
    "https://postsyncer.com/api/oauth/delegate/sessions",
    headers={"Authorization": f"Bearer {POSTSYNCER_API_KEY}"},
    json={
        "platform": "tiktok",
        "callback_url": "https://yourapp.com/postsyncer/callback",
        "state": state,   # random, persisted, single-use
    },
)
authorize_url = r.json()["authorize_url"]   # 2) redirect the user here

# 3) verify the signed callback
def verify(q, secret, expected_state):
    if q["state"] != expected_state: return False
    if int(q["expires"]) < int(time.time()): return False
    base = (f"platform={q['platform']}&platform_id={q['platform_id']}"
            f"&handle={q['handle']}&state={q['state']}&expires={q['expires']}")
    expected = hmac.new(secret.encode(), base.encode(), hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, q["sig"])
# 1) Create a delegation session (server-side)
curl -X POST https://postsyncer.com/api/oauth/delegate/sessions \
  -H "Authorization: Bearer $POSTSYNCER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
        "platform": "tiktok",
        "callback_url": "https://yourapp.com/postsyncer/callback",
        "state": "a1b2c3d4"
      }'

# Response → redirect the user to authorize_url
{ "authorize_url": "https://app.postsyncer.com/oauth/delegate?request=psd_…",
  "expires_in": 900 }

# 2) PostSyncer redirects back to your callback_url with:
#   ?platform=tiktok&platform_id=_000abc&handle=jane
#   &state=a1b2c3d4&expires=1717000000&sig=4d6c…e1

Prefer to test first? Point callback_url at the built-in local tester and PostSyncer will report each verification check for you. See the full API reference.

Verifiable by design

Every successful proof is signed with HMAC-SHA256 over a fixed base string using the signing secret tied to your API key. Recompute it on your server and compare in constant time:

base = "platform={platform}&platform_id={platform_id}"
     + "&handle={handle}&state={state}&expires={expires}"

sig  = HMAC_SHA256(base, your_signing_secret)

Generate your signing secret in Settings → API Keys in the PostSyncer app - click the shield "Generate signing key" button on the key's row. It is shown once; regenerating invalidates the previous secret.

Build it yourself vs. PostSyncer delegation

Build OAuth yourself PostSyncer delegation
Platforms to integrate One per network, separately A single API for all of them
App reviews & approvals Per platform, ongoing Already handled by PostSyncer
Token storage & refresh You build and secure it Not your problem
Ownership proof You design it Signed HMAC-SHA256 out of the box
Time to first verification Weeks 5 Minutes

Who uses OAuth delegation

Any product that needs to know a user truly owns a social handle.

Creator marketplaces

Confirm a creator really controls the handle before paying out, listing, or ranking them.

Brand & influencer platforms

Verify account ownership during onboarding without ever storing platform credentials.

Reward & loyalty apps

Tie rewards to a verified, permanent platform id that can't be spoofed or transferred.

Social login & KYC flows

Add "verify your social" as a trust signal alongside your existing identity checks.

Giveaway & UGC tools

Make sure entries come from real, owned accounts before counting them.

Agencies & SaaS

Onboard client accounts with verifiable proof, then manage them with the PostSyncer API.

Smart Tools Background
PostSyncer Logo
Got Questions?

Frequently Asked Questions

Everything developers ask about verifying social account ownership

OAuth delegation lets a third-party app connect a user's social media account through PostSyncer and receive back a cryptographically signed proof of ownership. Instead of registering and maintaining an OAuth integration with every platform (TikTok, Instagram, X/Twitter, LinkedIn, YouTube, and more), you reuse PostSyncer's existing integrations and verify the result with an HMAC-SHA256 signature.

You redirect the user into the PostSyncer delegation flow for that platform. After they authorize, PostSyncer returns the platform's permanent user id (such as a TikTok open_id or X user_id), the handle, an expiry timestamp, and an HMAC-SHA256 signature. You recompute the signature with your signing secret; if it matches and has not expired, you can trust the platform id as verified ownership proof.

No. Your API key is a full-access secret, so delegation starts with a server-to-server call from your backend (the key travels in the Authorization header). PostSyncer returns an opaque, single-use authorize URL, and only that token ever touches the user's browser.

Any platform PostSyncer supports that uses standard OAuth: TikTok, Instagram, X (Twitter), LinkedIn, YouTube, Facebook, Pinterest, and Threads. Credential-based platforms (Bluesky, Telegram) and instance-based Mastodon are not part of the delegation flow.

No. The platform id and handle are read directly from the platform's OAuth response and passed through to your callback. Nothing about the connection is persisted on your behalf beyond the API key's signing secret.

PostSyncer signs the string platform={platform}&platform_id={platform_id}&handle={handle}&state={state}&expires={expires} with HMAC-SHA256 using your signing secret. Your server recomputes the same HMAC and compares it in constant time, checks that the state matches what you issued (single use), and confirms expires is in the future.

Each signed callback includes an expires timestamp set five minutes in the future. Treat any proof received after that as expired and reject it.

In the PostSyncer app, open Settings → API Keys and click the “Generate signing key” (shield) button on the API key you want to use. The secret is shown once; regenerating it invalidates the previous one.

Ready To Grow Without The Guess Work?

Join 75,000+ creators and teams scaling their content
with
PostSyncer
PostSyncer