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:
Authorization: Bearer <access_token>
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, sending the authorization code, your client_id, your client_secret, and the PKCE code verifier. Fanvue returns an access token and a refresh token.
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 the same refresh token again within 30 seconds of it being rotated, Fanvue replays the original response — you get back the exact same access token and refresh token the first call returned, and the chain is not broken. This makes refreshes idempotent within the window, so a network retry or two requests firing at once won’t lock 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. The 30-second grace period now absorbs accidental double-use and retries — a duplicate call inside the window replays the same tokens instead of breaking the chain — but treat that as a safety net, not a substitute for serialising: a double-use that lands after the window still 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:
curl https://api.fanvue.com/users/me \
  -H "Authorization: Bearer eyJhbGc..."
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 permissions your app can request and what each one unlocks.