How wbps integrates with TikTok

A technical walkthrough of the OAuth and Content Posting API flow.

1. Sign in with TikTok (OAuth 2.0)

When you click Sign in with TikTok, your browser is redirected to:

https://www.tiktok.com/v2/auth/authorize/?client_key=…&response_type=code&scope=user.info.basic,video.upload,video.publish&redirect_uri=https://page.fvz.ai/api/auth/callback&state=…

wbps generates a cryptographically random state, signs it into a short-lived HttpOnly cookie, and validates it on return to defeat CSRF.

2. Token exchange

TikTok redirects back to /api/auth/callback with a one-time code. wbps exchanges it server-side at https://open.tiktokapis.com/v2/oauth/token/ with grant type authorization_code. The response contains access_token (24 h), refresh_token (1 year), open_id and the granted scope.

wbps stores the token bundle in Cloudflare KV keyed by an opaque session id, and sets a single HttpOnly tt_session cookie on your browser. The access_token is never sent to the browser.

3. Reading user info

wbps calls https://open.tiktokapis.com/v2/user/info/?fields=open_id,union_id,avatar_url,display_name with Authorization: Bearer <access_token> to populate the dashboard greeting.

4. Temporary video staging

When you submit the publish form, the browser first uploads the selected video to /api/upload. wbps stores it as a temporary Cloudflare R2 object owned by your current session and returns a video_key. The browser then sends that key and the post settings to /api/publish.

5. Initialising a Direct Post

wbps reads the temporary R2 object metadata, calls creator_info/query for the allowed privacy options, then POSTs to https://open.tiktokapis.com/v2/post/publish/video/init/ with a JSON body:

{
  "post_info": {
    "title": "<your caption>",
    "privacy_level": "<selected privacy option>",
    "disable_duet": false,
    "disable_comment": false,
    "disable_stitch": false,
    "video_cover_timestamp_ms": 1000
  },
  "source_info": {
    "source": "FILE_UPLOAD",
    "video_size": <bytes>,
    "chunk_size": <bytes>,
    "total_chunk_count": <n>
  }
}

TikTok responds with a publish_id and a signed upload_url.

6. Chunked upload

wbps reads the temporary R2 object in byte ranges and sends each chunk to upload_url with PUT and Content-Range: bytes start-end/total. The temporary R2 object is deleted after the publish request finishes.

7. Polling status

While the upload finishes server-side, wbps polls https://open.tiktokapis.com/v2/post/publish/status/fetch/ with {"publish_id": "…"} until the status reaches PUBLISH_COMPLETE, SEND_TO_USER_INBOX or FAILED.

8. Webhooks

TikTok delivers post-status notifications to https://page.fvz.ai/api/webhook. wbps verifies the TikTok-Signature header by computing HMAC-SHA256(client_secret, "<t>.<raw_body>") in constant time, deduplicates by event_id, persists the event in Cloudflare KV for 30 days, and immediately returns 200 as required by the spec.

9. Logout / Revocation

Clicking Sign out POSTs to https://open.tiktokapis.com/v2/oauth/revoke/ with the access_token, then deletes the session from KV and clears the tt_session cookie.

10. Sandbox mode

While the app is in TikTok's sandbox, all posts are forced to privacy_level = SELF_ONLY, and only TikTok accounts added to the app's Target Users list are allowed to authorise. This is intentional and is exactly the configuration recorded in the App Review demo video.

Endpoints reference