Skip to main content
OAuth gives you a connection. UX guidance on what to do with that connection — how to surface it, how to handle revocation, when to silently refresh vs prompt — is what separates a polished integration from a fragile one.
Two surfaces share the name “apps” — don’t conflate them. This page is about the “Connected to Flexslot” card you build inside your product, where your end users see and disconnect their Flexslot connection. Separately, you (the partner) manage your own OAuth clients — client_id, secret, redirect URIs — from Account → API access on flexslot.gg. See Managing OAuth Clients for that.

What good looks like

A well-built OAuth integration:

Names the connection clearly

“Connected to Flexslot as @username”, not “Token saved”.

Shows status, not just a button

Green check when healthy, yellow warning when reconnect needed, red when broken.

Handles 401 invisibly when possible

Silent refresh before the user notices. Prompt re-consent only when the refresh fails.

Provides a clear disconnect

One click. Calls /revoke. Confirms with the user. No leftover state.

The connection card

Most apps put the Flexslot connection on a Settings → Integrations page. Here’s a baseline pattern:
When disconnected:
When the grant was revoked or the refresh expired:

Handling 401 from the API

A 401 on a normal API call means the access token failed. Three cases, three different responses:
1

Token expired (most common)

Refresh silently. The user sees nothing. If you proactively refresh 5 minutes before expiry, this should be rare.
2

Refresh succeeds, retry succeeds

Replace stored tokens, retry the original request. The user still sees nothing.
3

Refresh fails with invalid_grant

The grant was revoked — either by the user from /account/connected-apps, by Flexslot for suspected token abuse, or by your own bug (refresh token replay). Mark the user as disconnected and prompt them to reconnect.

Don’t loop

If a refresh succeeds but the retried call still 401s (e.g. FLEXSLOT_OAUTH2_TOKEN_EXPIRED or FLEXSLOT_AUTHENTICATION_FAILED), don’t refresh again. That’s a bug pointing at your code, not at the user. Surface the error to your monitoring and show a polite error to the user — don’t infinite-loop the AS.

Token-bus pattern for parallel requests

A common source of invalid_grant storms: 10 in-flight requests all 401 at once, each independently tries to refresh, only one wins, the other 9 use the old refresh token, grant gets revoked. Pattern: a single token coordinator per user.
Across processes (a horizontally scaled service), use Redis with SET NX or a database row lock.

The user revoked you

A user can revoke your access at any time from flexslot.gg/account/connected-apps. You won’t know until the next API call returns 401 and your refresh returns invalid_grant. Don’t treat this as an error.
  • Mark the user as disconnected (clear the tokens).
  • Don’t email them about it (they revoked you on purpose).
  • Don’t try to reconnect silently.
  • The next time they use a Flexslot-dependent feature, show “Reconnect Flexslot”.
If your app sends scheduled or background sync jobs to Flexslot, stop them immediately when the grant is revoked. Repeated 401s on a revoked grant can trip Flexslot’s rate-limit and abuse heuristics.

When to start the flow

Naming the connection

In your UI, refer to it consistently:
  • “Flexslot” — the platform
  • “Connected to Flexslot” — past tense, the state
  • “Connect Flexslot” — the call to action
  • “Flexslot account” — the user’s identity on flexslot.gg
Avoid “your Flexslot token” or “Flexslot API key” in user-facing copy. Those leak implementation details.

Showing what you can see

Users trust apps that are upfront about what they’re doing. On the connection card, list the scopes in plain language:
You can fetch the current granted scopes from your stored token (you got them back on the /token response) or by calling /introspect.

The Disconnect flow

1

User clicks Disconnect

Confirm with a modal: “Disconnect from Flexslot? Your synced data will stay; future syncs will stop until you reconnect.”
2

On confirm, call /revoke

POST the refresh token to https://api.flexslot.gg/api/public/v1/oauth/revoke. RFC 7009 always returns 200 — don’t worry about the response.
3

Clear your tokens

Delete access_token, refresh_token, expires_at from your store. Don’t delete the user’s synced Flexslot data unless they ask — they may reconnect later.
4

Update the UI

Switch the card to “Not connected” state.

Edge cases

Identifying the user across sessions

Two endpoints, two jobs:
  • GET /_probe/user is what you call to render the connection card. With the user’s access token it returns user.id (the bare, stable Firebase id — identical to author.id on that user’s public decks) and user.username (the handle shown on the consent screen, e.g. george-cardeio). No extra scope is required; identity here is exactly what the user approved at consent. Treat username as a mutable display field and user.id as the stable correlation key. The user’s email is not returned — it isn’t consistently shown at consent, so it would be undisclosed PII; if you need to contact the user, ask them in your own product. See the quickstart for the full response shape.
  • POST /introspect is a token-metadata endpoint (RFC 7662), not an identity endpoint. Its username field carries the stable Firebase id (the same value as _probe/user’s user.id), not a display name. There is no sub claim — this is a plain OAuth 2.0 authorization server, not OIDC. Use /introspect to check whether a token is live and what it’s scoped to; use _probe/user to show who’s connected.
The caller field on _probe/user (partner:<slug>+user:<firebaseId>) is an opaque composite principal for rate-limiting and audit — stable, but don’t display it. Key your own profile store on user.id, which is the same firebase id /introspect returns as username.

User’s refresh token approaches expiry

Refresh tokens live 30 days from issue or last use. If the user opens your app once a week, their token will essentially never expire because every use extends it. If your app is used infrequently, expect cold-start 401s — handle them gracefully with a re-auth prompt.

Multiple browser tabs

If your app is a web SPA and the user has it open in two tabs, both tabs may try to refresh. See the token-bus pattern above, or use a BroadcastChannel to coordinate.

Background sync vs interactive use

Background workers using a user’s tokens are subject to the same lifetimes as foreground requests. If a background sync fails with invalid_grant, don’t retry — wait for the user to reconnect interactively. Background retries on a revoked grant can be flagged as abuse.

Patterns to avoid

Good OAuth UX is invisible when everything’s working and helpful when something breaks. If a user can’t tell whether they’re connected, you have a UX bug. If they can’t tell why they’re disconnected, you have another.