OAuth apps
Register an OAuth app, send creators, fans or agencies through the authorization-code flow with PKCE, and keep their tokens fresh with rotating refresh tokens.
API v1 at https://api.dropfans.io is authorized with OAuth 2.0 access tokens instead of API keys: the account (a creator, a fan or an agency) signs in on Dropfans, approves the scopes your app asks for, and your app receives a token that acts for that account. The authorization server is https://auth.dropfans.io, with OpenID Connect on top.
Register your app#
- Apply for API access and wait for the app to be approved.
- Ask the Dropfans team for an OAuth client for that app, with the redirect URIs you will use (exact https URLs;
http://localhostis fine for development) and the scopes it needs. - You receive a client id and a client secret. The secret is shown once: store it server-side only. If it leaks, ask for a new one; the old one stops working immediately.
Each API category of your app (chat, posts, vault, …) has its own switch on our side, so a scope you were granted can still answer 404 while its category is off for your app.
Endpoints#
| Endpoint | Purpose |
|---|---|
GET https://auth.dropfans.io/oauth2/auth | Authorization: the account signs in and approves your scopes |
POST https://auth.dropfans.io/oauth2/token | Exchange a code, or refresh a token |
POST https://auth.dropfans.io/oauth2/revoke | Revoke an access or refresh token (and its whole grant) |
GET https://auth.dropfans.io/userinfo | OpenID Connect claims of the token’s account |
GET https://auth.dropfans.io/.well-known/openid-configuration | Discovery document |
GET https://auth.dropfans.io/.well-known/jwks.json | Keys that sign the id_token (RS256) |
GET https://auth.dropfans.io/oauth2/sessions/logout | End-session endpoint |
Read the endpoints from discovery rather than hard-coding them where your OAuth library supports it.
1. Send the account to the authorization endpoint#
PKCE with S256 is required for every client: create a random code_verifier, send code_challenge = BASE64URL(SHA256(code_verifier)). Requests without it, or with plain, are refused.
GET https://auth.dropfans.io/oauth2/auth?response_type=code
&client_id=YOUR_CLIENT_ID
&redirect_uri=https%3A%2F%2Fapp.example.com%2Fcallback
&scope=openid%20offline_access%20read%3Aself%20read%3Achat
&state=RANDOM_STATE
&code_challenge=BASE64URL_SHA256_OF_VERIFIER
&code_challenge_method=S256redirect_uri must match a registered URI exactly. scope is space-separated; scopes your client is not allowed, or that the account type cannot hold, are left out of the grant (check scope in the token response). The account comes back to your redirect_uri with code and your state, or with error and error_description.
The code is single-use and expires after 60 seconds. Presenting a code twice revokes every token it produced.
2. Exchange the code#
Authenticate the client with HTTP Basic (client_secret_basic: client_id:client_secret, base64). It is the only client authentication method.
curl -X POST https://auth.dropfans.io/oauth2/token \
-u "$CLIENT_ID:$CLIENT_SECRET" \
-d grant_type=authorization_code \
-d code="$CODE" \
-d redirect_uri=https://app.example.com/callback \
-d code_verifier="$CODE_VERIFIER"{
"access_token": "…",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "openid offline_access read:self read:chat",
"refresh_token": "…",
"id_token": "eyJ…"
}refresh_token is only issued when the grant includes offline_access (or offline); id_token only with openid. Its sub is the account’s UUID, the same uuid that GET /users/me returns.
3. Call the API#
curl https://api.dropfans.io/v1/users/me -H "Authorization: Bearer $ACCESS_TOKEN"See API v1 overview for paging, versions, errors and limits.
4. Refresh#
curl -X POST https://auth.dropfans.io/oauth2/token -u "$CLIENT_ID:$CLIENT_SECRET" \
-d grant_type=refresh_token -d refresh_token="$REFRESH_TOKEN"Refresh tokens rotate: every refresh returns a new access token and a new refresh token, and the one you sent stops working. Store the new pair before using it. If the same refresh token is presented again within 60 seconds (a retried request), you get the same new pair back; after that, reuse is treated as theft and the whole grant is revoked. The account then has to authorize your app again.
Token lifetimes#
| Token | Lifetime |
|---|---|
| Authorization code | 60 seconds, single use |
| Access token | 60 minutes |
| Refresh token | 30 days from issue; each refresh starts a new one |
id_token | 60 minutes |
Revoke#
curl -X POST https://auth.dropfans.io/oauth2/revoke -u "$CLIENT_ID:$CLIENT_SECRET" -d token="$TOKEN"Revoking either token ends the grant. Webhook deliveries for that account stop as soon as no live grant of your app is left. Accounts can also disconnect your app themselves.
Userinfo#
GET /userinfo with the access token returns sub (the account UUID), plus preferred_username, name, picture, email and email_verified when the grant includes read:self.
Scopes#
System scopes: openid, offline_access, offline (openid adds an id_token; offline_access or offline adds a refresh token). API scopes, and which account types can hold them:
| Scope | Grants | Fan | Creator | Agency |
|---|---|---|---|---|
read:self | Read your profile and account details | ✓ | ✓ | ✓ |
read:chat | Read your chats and messages | ✓ | ✓ | ✓ |
write:chat | Send messages and manage chats | ✓ | ✓ | ✓ |
read:experience | Read fan-facing experiences (not served yet) | ✓ | ✓ | ✓ |
write:experience | Publish or unpublish fan-facing experiences (not served yet) | — | ✓ | ✓ |
read:fan | Read your fans and their activity | — | ✓ | ✓ |
read:post | Read your posts, comments and likes | — | ✓ | ✓ |
write:post | Create, edit and delete posts | — | ✓ | ✓ |
read:media | Read your vault media | — | ✓ | ✓ |
write:media | Upload and manage vault media and folders | — | ✓ | ✓ |
read:creator | Read creator profiles and the creators you manage | — | ✓ | ✓ |
write:creator | Change creator profile and settings | — | ✓ | ✓ |
read:insights | Read earnings and audience insights | — | ✓ | ✓ |
read:tracking_links | Read tracking links and who joined through them | — | ✓ | ✓ |
write:tracking_links | Create and delete tracking links | — | ✓ | ✓ |
read:agency | Read your agency and its team | — | — | ✓ |
write:agency | Manage agency invites and team members | — | — | ✓ |
Each API v1 operation needs every scope listed for it in the resource list; a token without them gets 403 {"error":"Insufficient scopes"}.
Errors#
The authorization and token endpoints answer in the standard OAuth form {"error": "invalid_grant", "error_description": "…"} (invalid_request, invalid_client, invalid_grant, invalid_scope, unsupported_grant_type, access_denied, …). The token endpoint allows 120 requests a minute per client and 60 per IP address.
Questions? [email protected]
