Skip to main content
The Fanvue API uses OAuth 2.0, the standard protocol that lets a user grant your app access to their account without ever handing over their password. The user authorizes your app, Fanvue gives you an access token (a short-lived credential called a Bearer token), and you call the API on their behalf by sending that token on every request:
There are no API keys to copy, paste, or leak. Access is always tied to a specific user and the scopes they approved.

The flow at a glance

The flow, step by step

1

Send the user to Fanvue to authorize

Your app redirects the user to the Fanvue authorize URL at https://auth.fanvue.com/oauth2/auth. The URL carries your client_id, the redirect URI (the page on your app Fanvue sends the user back to), the scopes you need, a random state value (to prevent cross-site request forgery), and a PKCE code challenge.
2

The user logs in and grants scopes

On Fanvue, the user signs in and approves the exact permissions your app asked for. They stay in control: they only grant the scopes you requested, and they can revoke access later.
3

Fanvue redirects back with an authorization code

Fanvue sends the user back to your redirect URI with a short-lived authorization code in the query string. This code is a one-time voucher, not a usable credential on its own. Verify the returned state matches the one you sent.
4

Exchange the code for tokens

Your backend makes a server-to-server call to https://auth.fanvue.com/oauth2/token, authenticating with your client_id and client_secret in an HTTP Basic Auth header (client_secret_basic), and sending the authorization code and PKCE code verifier in the body. Fanvue returns an access token and a refresh token. See the implementation guide for the exact request.
5

Call the API on the user's behalf

Send the access token on every request to https://api.fanvue.com in the Authorization: Bearer <token> header. When the access token expires (typically after an hour), use the refresh token to get a new one without sending the user through the flow again.

How tokens work

The token exchange (step 4) returns two tokens that do different jobs:
  • Access token, a short-lived Bearer credential (typically valid for 1 hour) that you send on every API request. It carries the scopes the user approved. When it expires, the API responds with 401 Unauthorized.
  • Refresh token, a longer-lived credential you keep server-side and use to obtain a new access token when the current one expires, without sending the user back through the authorize flow. Request the offline_access scope to receive one.
To refresh, your backend calls the token endpoint with grant_type=refresh_token. The response returns a new access token and a new refresh token.

Refresh tokens rotate and are single-use

Each refresh token can be used exactly once. Every refresh returns a new refresh token, and the previous one stops working straight away. Always persist the new refresh token from the response and discard the old one.A 30-second grace period covers retries and races. If you present an already-rotated refresh token again within 30 seconds, Fanvue accepts it instead of tripping reuse detection, and the chain is not broken. Each accepted call mints a new access token and a new refresh token, so you never get the earlier pair back. The refresh token you presented is consumed either way, so persist whatever the newest successful response returned before you do anything else with it. That is what stops a network retry or two requests firing at once from locking you out.Reusing a refresh token after the grace period breaks the refresh chain. If a token that has already been used is presented again once the 30-second window has passed (or a token that is otherwise invalid is presented), Fanvue treats it as a sign the token may be compromised, invalidates the entire refresh token chain (every refresh token issued from that authorization) and the refresh fails. Access tokens are short-lived JWTs that aren’t revoked: any access token you already hold keeps working until it expires, but you can no longer mint new ones, so once the current access token lapses you’re locked out. The only way to recover is to send the user through the full OAuth authorization flow again from step 1.
This is standard OAuth refresh token rotation with reuse detection. It protects creators: if a refresh token is ever stolen, the moment either the attacker or your app uses the stale copy after the grace period, the refresh chain is invalidated, no new access tokens can be minted, so the session can’t be kept alive past the current access token’s expiry. What this means for your implementation:
  • After every refresh, overwrite your stored refresh token with the new one from the response. Treat the old value as dead.
  • Still avoid refreshing the same token twice. Serialise concurrent refreshes (use a lock or a shared promise) so two requests can’t both fire with the same refresh token, and never run two refreshes for the same chain at the same time. The 30-second grace period absorbs accidental double-use and retries, but each accepted call returns a different token pair, so treat it as a safety net rather than a substitute for serialising: a double-use that lands after the window still breaks the chain.
  • If a refresh response is lost, ambiguous, or times out, re-exchange immediately. Presenting the same refresh token again inside the 30 seconds is the safe recovery path: it is accepted, and it returns a fresh pair you can store. Waiting until the window has passed and retrying then trips reuse detection and breaks the chain.
  • Never run multiple workers off one shared refresh token without coordinating who refreshes.
  • If a refresh fails with invalid_grant, assume the refresh chain is broken and redirect the user to re-authorize. Do not retry the refresh.
See the implementation guide for the exact refresh request, response shape, and a client that handles rotation, locking, and retry safely.

PKCE is required

PKCE (Proof Key for Code Exchange) is mandatory on every Fanvue OAuth flow. It closes a gap in the authorization code flow: if someone intercepts your authorization code, they still cannot exchange it for tokens.
1

Generate a verifier and a challenge

Before redirecting the user, your app creates a random code_verifier and a code_challenge, which is the SHA-256 hash of the verifier. You send the challenge in the authorize URL (step 1) and keep the verifier server-side.
2

Prove it on token exchange

When you exchange the code for tokens (step 4), you send the original code_verifier. Fanvue hashes it and confirms it matches the challenge from step 1. No match, no tokens.
Store the code_verifier server-side (in a session, Redis, or an HttpOnly cookie) between the redirect and the token exchange. Never put it in local storage, a URL, or client-side JavaScript.

A token in action

Once you hold an access token, every API call looks like this:
The full request and response shapes for the authorize and token endpoints, including refresh and error handling, live in the implementation guide.

Where to go next

Quick start

Create an OAuth app and run the full flow end to end with a working Next.js example.

Implementation guide

Every endpoint, parameter, and code sample: PKCE, token exchange, refresh, and error handling.

Scopes

The full list of scopes your app can request and what each one unlocks.