Authentication
API key header
Send your key on every request:
XF-Api-Key: <your-api-key>
That is all a server-to-server or game-client integration needs. The key already carries its scopes and its game restriction.
Acting as a specific user (optional)
Only needed if you act as a forum user - e.g. letting a logged-in player post a review through your client. Add:
XF-Api-User: <user_id>
For read-only mod browsing you do not need it.
This header only works on a super-user key, which can act as any account. Super-user keys are never issued for distributable clients (tools, launchers, game builds). If a player needs to act as themselves, use OAuth2 (below).
Scope behavior
- A key bound to one or more games is game-scoped: every list is auto-filtered to those games, and a direct lookup of an out-of-scope record returns 403.
- A key bound to zero games is unrestricted - the mod-manager / launcher tier, browsing all public games.
You never pass a game_id to "pick" a game. Scope is enforced server-side.
NSFW exclusion
If a game is flagged to exclude NSFW from API/in-game access (the default), the API never returns NSFW-marked mods for it, on any key tier. The website still shows them behind its own adult gate - the API surface is the compliance-safe subset. This is a per-game setting, not something the key toggles.
Keep your key safe
How careful you need to be depends on where the key lives:
- On a server you control (your backend, a proxy): keep it in an environment variable or secret store, never in a public repo.
- Inside a distributable client (a desktop tool, a launcher, a game build): assume anyone can extract it. Keys for distributable clients are therefore read-only: they carry only read scopes, so an extracted key cannot post, edit or delete anything. Tool keys (mod managers, update checkers) are Guest keys that see exactly what a logged-out visitor sees.
- A key can be revoked and replaced at any time. If yours leaks or gets abused, contact us and we rotate it.
- Never ship a super-user key, or any key with write scopes, in something you distribute.
If you want the key out of the binary entirely, run a small proxy server that holds the key and have your client call the proxy. See also Ownership & anti-piracy.
Player login/register in a launcher (OAuth2)
XF-Api-Key is for your server or client acting as itself - browsing, listing, downloading. It has no concept of "a player logging in." If your launcher needs a real player to sign in (or register a new account) and then act as themselves - post a review, favorite a mod, see their own library - use OAuth2 instead. Do not try to fake this with XF-Api-User: that header only works on a super-user key and lets the key impersonate any account by ID with no login step at all, which is not a login flow and not safe to ship in a client.
1. Register your client (one-time, ask a site admin)
An admin creates an OAuth2 client in the AdminCP (Setup > Service providers > OAuth2 clients), giving you:
client_id- a
redirect_uriyour launcher listens on. It must behttporhttps; custom schemes such asmyapp://callbackare rejected. For a desktop app, use a local loopback listener such ashttp://127.0.0.1/callback: on127.0.0.1(and[::1]) any port matches the registered URI, so you can bind a free port at runtime. This does not apply tolocalhost, which must match the registered port exactly. - a client type: Public for a launcher/desktop app (recommended - a distributed binary cannot keep a secret), Confidential only if the token exchange happens on a server you control
Public clients must use PKCE (below) since they have no client_secret.
2. Send the player to authorize
Open the system browser (not an embedded webview, so the player's existing session/password manager works) to:
https://ayakamods.com/oauth2/authorize?client_id=YOUR_CLIENT_ID
&response_type=code
&redirect_uri=YOUR_REDIRECT_URI
&scope=mod:read+mod_rating:read
&state=RANDOM_STRING
&code_challenge=CODE_CHALLENGE
&code_challenge_method=S256
If the player isn't logged in, XenForo shows its normal login and register page first, then the consent screen, then redirects back to your redirect_uri with a code. This is the whole point - AyakaMods doesn't need its own login/register API, XenForo's is reused as-is.
PKCE (code_verifier / code_challenge): generate a random code_verifier, send code_challenge = base64url(sha256(code_verifier)) here, and send the raw code_verifier in the token exchange below. Required for public clients.
3. Exchange the code for a token
curl https://ayakamods.com/api/oauth2/token \
-d grant_type=authorization_code \
-d client_id=YOUR_CLIENT_ID \
-d code=THE_CODE_FROM_STEP_2 \
-d redirect_uri=YOUR_REDIRECT_URI \
-d code_verifier=YOUR_CODE_VERIFIER
Response:
{
"access_token": "...",
"refresh_token": "...",
"token_type": "bearer",
"expires_in": 3600,
"scope": "mod:read mod_rating:read"
}
4. Call the API as that player
curl https://ayakamods.com/api/mods/ \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
No XF-Api-Key needed on these calls - the Bearer token identifies the player directly, and normal site permissions apply to them. When access_token expires, use grant_type=refresh_token with your refresh_token to get a new pair without asking the player to log in again.
5. Signing out
Public clients cannot call the token revoke, introspect or info endpoints, because those require a client_secret. To sign a player out, delete the stored access and refresh tokens on the device. Access tokens expire on their own after expires_in seconds (3600).
Note on game scoping: OAuth tokens act as the logged-in player, not as a developer's game-restricted key - they are not narrowed to your game the way an XF-Api-Key is. Use OAuth only for player-identity actions (login, reviews, favorites); keep using your game-scoped XF-Api-Key for everything else (listing/downloading your game's mods).