OAuth 2.0
Authorization code with PKCE, token lifetimes, refresh, revoke and redirect URI rules.
All clients use the authorization code flow with PKCE (S256), including confidential clients. Implicit and password grants are not supported.
Client types
confidential("Web app with a backend"): your backend keeps the client secret and exchanges the code. It is the only app type for now.- Mobile, desktop and browser-only apps use the same type through a backend ("backend for frontend"): the app opens the system browser on the authorization URL, FleetBold redirects to your backend, and your backend keeps the secret and the tokens; the app talks to your backend. Embedded WebViews are not supported.
Authorization request
GET https://partners-api.fleetbold.com/oauth/authorize
?response_type=code
&client_id=fbci_…
&redirect_uri=https%3A%2F%2Fapp.example.com%2Foauth%2Fcallback
&scope=…
&state=…
&code_challenge=…
&code_challenge_method=S256- Read the authorization URL from
authorization_endpointinhttps://partners-api.fleetbold.com/.well-known/oauth-authorization-server(RFC 8414) instead of hard-coding it. redirect_urimust match a registered redirect URI exactly.scopeis space-delimited and must be a subset of the scopes your app can request. Scopes added to a live app after its review are pending: only you and your test users can grant them; for other users they are left out and the authorization continues with the rest (read the granted scopes fromscopein the token response). See Changing a live app.- Scopes your app marks as required are always added to the request, even when
scopeleaves them out; an emptyscopeasks for just the required scopes (RFC 6749 §3.3). Editingscopecan only drop optional scopes, never add one your app cannot request. - The app OAuth & permissions tab builds this URL for your app in the Authorization link card: a template with
{state}and{code_challenge}(and{nonce}withopenid) placeholders, plus Node.js and Python code that makes fresh values for every login. Never reuse astateorcode_challenge. stateis required (up to 512 characters);code_challengeis 43–128 characters. Send every parameter once (a repeated one is refused) and keep the URL under about 8 KB.- An unknown
client_id, an unregisteredredirect_urior a repeatedclient_id/redirect_urishows a FleetBold error page and never redirects. Other refusals are shown on a FleetBold page whose Return button redirects to yourredirect_uriwitherror,state,issand usuallyerror_description.
On FleetBold's page the user signs in with their FleetBold e-mail and password on every authorization (no single sign-on), then always sees the consent page, prefilled with what they shared before: your app, the scopes it asks for and which personal and organization vehicles to share. Scopes required by your app are ticked and locked: the user approves them or denies the connection; the other scopes can be unticked. The first time a user grants a high-risk scope the page asks for an extra confirmation. While your app is in development the page shows a "Development — not reviewed by FleetBold" warning. Approving redirects to your redirect_uri with code, state and iss (https://partners-api.fleetbold.com): check both state and iss. Deny redirects with error=access_denied (user_denied); Cancel on the sign-in page with error=access_denied and no description. Open the page in the system browser, never an embedded WebView, and never ask users for their FleetBold password yourself. To keep access without sending the user back, request offline_access and use refresh tokens.
Required scopes
- In OAuth & permissions, switch on Required for each scope your app cannot work without. The change applies at once, without a review; on a live app only approved scopes can be required.
- FleetBold adds the required scopes to every authorization request, so a link that leaves one out keeps working. The consent page marks them *Required by the app* and the user cannot untick them; a high-risk one still needs the extra confirmation.
- Existing connections that lack a newly required scope keep their tokens: FleetBold asks for the scope at their next authorization. The Overview connections table flags them.
- Removing a scope from your app also un-requires it.
openidmarked as required is ignored until FleetBold enables OpenID Connect (the Authorization link leaves it to FleetBold; anopenidlisted inscopeis refused until then).
Tokens
curl https://partners-api.fleetbold.com/oauth/token \
-d grant_type=authorization_code \
-d code=… \
-d redirect_uri=… \
-d code_verifier=… \
-u "$CLIENT_ID:$CLIENT_SECRET" # confidential clients only- Authorization codes live 60 seconds and work once.
- Access tokens are opaque Bearer tokens that live 1 hour.
- Refresh tokens (scope
offline_access) last 90 days, sliding, and are rotated on every use. The previous refresh token keeps working for a short grace window; reusing an older one revokes the whole token family. - Revoke with
POST /oauth/revoke. Revoking a refresh token disconnects the user.
Redirect URIs
- Web app with a backend:
https://app.example.com/oauth/callbackon your backend (also for mobile and desktop apps, which reach it through the system browser). - Up to 10 redirect URIs per app.
http://localhostredirects are allowed in development only and are rejected when you submit for review. After go-live, keep developing locally with a test app (see Changing a live app).
Disconnections
A user or FleetBold can disconnect your app. When a refresh answers 400 invalid_grant, the connection is gone: ask the user to connect again. 403 app_suspended is not a disconnection.