Where this sits
Note what Fluz absorbs in the middle of that diagram: account creation, sign-in, two-factor authentication, and identity verification if the user hasn’t been verified yet. You don’t build any of it, and you never see the credentials.
Before you start
1
Your app is configured
Scope ceiling set on the Permissions tab, redirect URI registered on the OAuth tab,
client_id and client_secret in your secret store. See Configure OAuth App.2
Your callback route exists and can reach your session store
It needs to read
state and compare it against something you persisted before the redirect.3
You know which scopes this flow needs
See Authentication for the full list. Request the minimum — the consent screen is your highest-drop-off step and its length comes from this list.
Step 1 — Build the authorize URL
Direct the user to the/authorize endpoint with the following query parameters.
Environments
Encoding rules
Spaces between scopes must be encoded as%20. URL-encode the redirect_uri value as well; build the query string with your language’s URL encoder rather than string concatenation, and these take care of themselves.
A complete staging example:
What the user sees
Your app name, avatar, and description come straight from the Overview tab, and the permission lines are your selected scopes grouped under readable headers. If this screen looks wrong, the fix is on Configure OAuth App, not in your code.
Step 2 — Protect the flow with state
The reference table calls state optional. In a redirect-based authorization flow it is your only defense against having someone else’s authorization code planted in your user’s session, so build it in from the first commit rather than adding it later.
1
Generate an unguessable value
At least 128 bits from a cryptographically secure source. Not a timestamp, not a user ID, not a counter.
2
Store it server-side, bound to the browser session
Session store, signed cookie, or short-TTL cache keyed to the session. Not in a global.
3
Compare on the way back, and reject on mismatch
Missing, unrecognized, or already-used
state means abandon the request — do not exchange the code. Use a constant-time comparison.4
Consume it
Delete it after a successful match so the same callback can’t be replayed.
state travels through the user’s browser. It’s fine to use it to carry a lookup key — which user, which flow, which page to return to — but never put anything sensitive or trusted in the value itself.Step 3 — Handle the callback
On approval, Fluz redirects the user to yourredirect_uri with:
If the request was misconfigured, the redirect carries an error message describing what didn’t match.
Step 4 — Reconcile what you actually got
The exchange response includes the scope array the user approved. That array, not your request, is the truth about what your integration can do. A scope you requested can be missing because the user declined it, or because it isn’t enabled on your app’s Permissions tab — in which case it was silently dropped rather than rejected. Either way the flow completes successfully and your API calls fail later. Read the returned scopes, persist them alongside the tokens, and gate your features on them. If something essential is missing, tell the user plainly and offer to re-run the flow.Designing the moment
The consent screen converts far better when the user understands why they’re seeing it.- Explain before you redirect. One sentence on your own page — “Connect your Fluz account so we can send your payouts” — outperforms dropping someone cold onto a permissions screen.
- Trigger it in context. At the point of first payout or first card, not buried in account settings.
- Full-page redirect over a popup. Popups get blocked, and the flow includes 2FA and possibly identity verification, which is uncomfortable in a small window. If you need to stay in-page, use an embedded widget instead, which is built for exactly that.
- Handle the return trip. Land the user where they were, with the thing they were trying to do now working.
stateis how you know where that was. - Have a re-authorization path. Refresh tokens expire and users revoke access. Build the “reconnect” flow at the same time as the connect flow, not after the first support ticket.
- Consider skipping it. If your users don’t already have Fluz accounts, a widget handles registration, verification, and consent in one hosted flow with no redirect. See Embedded Widgets.
Troubleshooting
Next steps
Exchange an authorization code
Turn the code into an access token and refresh token.
Refresh an access token
Stay connected without sending the user back through consent.
Configure OAuth app
Fix anything the consent screen got wrong.
Embedded widgets
Skip the redirect entirely with a hosted in-page flow.