OAuth is only as secure as the weakest link in your implementation. This page enumerates the practices Flexslot requires and the ones we strongly recommend. Most of these come straight from RFC 9700 (BCP 240, the OAuth 2.0 Security Best Current Practice). Treat them as MUSTs.Documentation Index
Fetch the complete documentation index at: https://docs.flexslot.gg/llms.txt
Use this file to discover all available pages before exploring further.
The non-negotiables
PKCE S256 always
Every flow, every client type.
plain is forbidden.Exact redirect URI match
No wildcards. No prefix matching. Byte-for-byte.
state on every request
Random, single-use, bound to the user’s session.
Validate iss on callback
RFC 9207. Reject if missing or wrong.
Refresh token rotation
Store the new token, drop the old.
HTTPS everywhere
No exceptions for production.
PKCE (Proof Key for Code Exchange)
What it does: binds the authorization code to your client, so an intercepted code is useless to anyone else. Required at Flexslot for:- Every client type — public and confidential.
- Every authorization code request.
S256. plain is rejected.
See Authorization Code Flow for working code in Node, Python, and bash.
redirect_uri matching
Flexslot performs exact string match on theredirect_uri parameter against the URIs registered for your client. There is no wildcard support, no path-prefix tolerance, and no port-flexibility (except 127.0.0.1 and [::1] for native apps’ loopback redirects).
| Registered URI | Request URI | Match? |
|---|---|---|
https://app.example.com/oauth/callback | https://app.example.com/oauth/callback | Yes |
https://app.example.com/oauth/callback | https://app.example.com/oauth/callback/ | No (trailing slash differs) |
https://app.example.com/oauth/callback | https://app.example.com/oauth/callback?foo=1 | No (query string differs) |
https://app.example.com/oauth/callback | https://APP.example.com/oauth/callback | No (case differs) |
https://app.example.com/oauth/callback | http://app.example.com/oauth/callback | No (scheme differs) |
Recommended practice
- One URI per environment. Register
https://dev.app.example.com/oauth/callbackANDhttps://app.example.com/oauth/callback. Don’t try to use one with a wildcard. - Avoid query strings. Keep state in a session, not in the URI.
- Use HTTPS.
http://is allowed only forlocalhost,127.0.0.1, and[::1](for local development and native apps).
state parameter
Thestate parameter is a CSRF token: it proves that the callback corresponds to a flow your application initiated.
Requirements
- Cryptographically random — at least 128 bits of entropy.
- Bound to the user agent’s session (a cookie, server-side session storage).
- Single-use — invalidate after the callback consumes it.
- Validated on callback — strict equality compared to the stored value.
What happens if you skip it
PKCE protects against code interception, butstate is the universally-compatible defense against the simpler attack of “trick the user’s browser into hitting your callback with an attacker-controlled code”. Without state, an attacker who can convince the user to visit a URL can bind the user’s session to the attacker’s Flexslot account.
Issuer identification (RFC 9207)
Every callback from Flexslot includes aniss query parameter:
iss == "https://api.flexslot.gg". If it’s missing or different, abort the flow — that’s a mix-up attack signal.
The mix-up attack: a malicious or compromised authorization server tricks your client into sending a code intended for AS A to AS B. The iss parameter cryptographically labels which AS issued the code so your client can tell.
Refresh token rotation
Every successfulgrant_type=refresh_token exchange:
- Returns a new refresh token in the response.
- Invalidates the refresh token you just used.
What this means for your code
Store the new refresh_token immediately
Atomically replace the old one in your database. The old one is dead.
Token storage
| Where | Acceptable for |
|---|---|
| Encrypted database column | Server-side apps — recommended |
| Encrypted Redis | Server-side apps — recommended |
| HTTP-only cookie | Refresh token for web apps using a BFF pattern |
| In-memory variable | SPA access tokens (no JavaScript-accessible storage) |
localStorage / sessionStorage | Never for tokens — XSS reads it all |
| URL query string | Never. RFC 9700 forbids tokens in URIs. |
| Server logs | Never. Mask tokens before logging. |
TLS
- All Flexslot endpoints require TLS 1.2 or higher.
- Loopback (
http://127.0.0.1) is allowed for development and native apps. - We send
Cache-Control: no-storeon every token response — your client should not cache them.
CSRF on the token endpoint
The token endpoint isPOST-only and requires either:
- HTTP Basic auth with the client credentials (for confidential clients), or
client_idin the form body plus the PKCEcode_verifier(for public clients).
/authorize is. CSRF protection on /authorize is the job of the state parameter.
Logging out / revocation
When a user logs out of your app:- Call
/revokewith their refresh token. This invalidates both the refresh token and any active access tokens for the grant. - Clear local state — remove tokens from your store.
200 with an empty body (RFC 7009).
When tokens leak
If a token is logged, exposed in an error page, or shows up in a screenshot — treat it as compromised and revoke it immediately, then rotate any related secrets. The 1-hour access token expiry limits blast radius, but a leaked refresh token is good for 30 days unless revoked.Sender-constrained tokens (DPoP / mTLS)
Bearer tokens are exactly that — whoever holds one can use it. For high-value integrations, consider sender-constraining with DPoP (RFC 9449) so that a stolen token can’t be replayed by an attacker who doesn’t have your client’s private key. See DPoP.Threats this defends against
| Threat | Defense | Where |
|---|---|---|
| Authorization code interception | PKCE | authorization-code-flow |
| CSRF on callback | state | This page |
| Mix-up attack | iss validation | This page |
Open redirector via wildcard redirect_uri | Exact URI match | This page |
| Refresh token theft | Rotation + revoke on replay | This page |
| XSS exfiltrating tokens | In-memory storage + httpOnly cookies | This page |
| Token replay across services | DPoP / mTLS sender constraint | DPoP |
Further reading
- RFC 9700 — The complete OAuth 2.0 Security BCP. Every implementer should read this once.
- RFC 9207 — Issuer Identification for mix-up defense.
- RFC 7636 — The PKCE spec.
- OWASP OAuth2 Cheat Sheet — Threat-to-mitigation mapping.