Skip to main content
Every request to the Fanvue API carries an OAuth 2.0 access token that a creator, fan or agency admin granted to your app. Fanvue issues no API keys, no personal tokens and no client-credentials grant, so every token comes from a user’s consent. Access is always tied to one user and the scopes they approved, and which scopes a user can grant depends on their account type; see Scopes by account type. There’s no public (PKCE-only) client either. Every app is a confidential client with a client secret, which means your token exchange runs on a server. You need an app from the Developer Area with its Client ID, Client Secret and a registered redirect URI. Start here to understand the flow; the implementation guide has the exact requests, and the Builder SDK runs the flow for you. You send the token as a Bearer credential on every request:

Flow diagram

The flow, step by step

1

Send the user to Fanvue to authorise

Your app redirects the user to https://auth.fanvue.com/oauth2/auth. The URL carries your client_id, your redirect_uri, the scopes you need, a random state value and a PKCE code challenge. The state value protects the callback against cross-site request forgery.
2

The user logs in and grants scopes

On Fanvue, the user signs in and approves the scopes your app asked for. Scopes the user’s account type cannot use are dropped from the grant. The user can revoke access later.
3

Fanvue redirects back with an authorisation code

Fanvue sends the user back to your redirect URI with a one-time authorisation code in the query string. The code is a voucher, not a credential. Check that the returned state matches the one you sent.
4

Exchange the code for tokens

Your backend calls https://auth.fanvue.com/oauth2/token with your client_id and client_secret in an HTTP Basic Auth header (client_secret_basic). The body carries the authorisation code and the PKCE code verifier. Fanvue returns an access token and a refresh token. The implementation guide shows 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, use the refresh token to get a new one without sending the user through the flow again.

A token in action

Every API call carries the access token and the version header:

PKCE is required

PKCE (Proof Key for Code Exchange) is mandatory on every Fanvue OAuth flow. It stops an intercepted authorisation code from being exchanged for tokens.
1

Generate a verifier and a challenge

Before redirecting the user, your app creates a random code_verifier and a code_challenge, the SHA-256 hash of the verifier. You send the challenge in the authorise URL and keep the verifier server-side.
2

Prove it on token exchange

When you exchange the code for tokens, you send the original code_verifier. Fanvue hashes it and compares the result with the challenge. No match, no tokens.
Store the code_verifier server-side, in a session store or an HttpOnly cookie, between the redirect and the token exchange. A verifier in local storage, a URL or client-side JavaScript is readable by injected scripts, and a stolen verifier plus an intercepted code yields tokens. If you can’t find the verifier on the callback, abandon the attempt and start the flow again.

How tokens work

The token exchange returns two tokens with different jobs:
  • Access token: a short-lived Bearer credential 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. 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 is accepted once. Persist the new refresh token from every refresh response and discard the old one. A short grace window after rotation absorbs a retry or a race, and each call accepted inside it returns a new token pair.
Presenting a rotated refresh token after the grace window trips reuse detection. Fanvue invalidates every refresh token issued from that authorisation and the refresh fails with invalid_grant. Access tokens you already hold keep working until they expire, then the user is locked out. The only recovery is to send the user through the full authorisation flow again.
Reuse detection protects creators. If a refresh token is stolen, the first stale use after the grace window breaks the chain, so a stolen token can’t keep a session alive past the current access token’s expiry. Rules for your implementation:
  • Overwrite your stored refresh token after every refresh. Treat the old value as dead.
  • Serialise refreshes with a lock or a shared promise so two requests never present the same refresh token. The grace window is a safety net, not a substitute.
  • If a refresh response is lost or times out, re-present the same refresh token straight away. Waiting past the grace window and retrying then breaks the chain.
  • Never run several workers off one refresh token without coordinating which one refreshes.
  • Treat invalid_grant on a refresh as a broken chain. Don’t retry the refresh; redirect the user to authorise again.
The implementation guide has the refresh request, the response shape and a client that serialises refreshes.