Authorizing an app against an AppBO account: the handshake, token refresh, scope management and handling revocation.
Bring your stack to a call and we will connect it, test every field in both directions, and hand it over documented.
Book a callOAuth is the handshake that lets an application act on an AppBO account without ever holding the account owner's password. On one side is your application: registered once, holding a client identifier and a client secret. On the other is an account owner or agency administrator who clicks through a consent screen and grants your app a named set of permissions against a named account. What comes back is a short-lived access token, a longer-lived refresh token, and a record of exactly which account and which scopes the grant covers.
You wire this up whenever more than one account will ever use your integration, or whenever the thing being connected is a product rather than a one-off script. A single private key hard-coded into a cron job is fine for your own account; it is unworkable the moment a second client needs it, because you would be asking that client to hand over credentials that cannot be scoped or revoked independently.
There are two shapes of grant worth distinguishing. A sub-account (location) grant authorizes your app against one account's data. An agency grant authorizes your app at the parent level, after which it can obtain tokens for the accounts beneath it. Agency grants are the right model for a product that serves an agency's whole client roster; they are also the one most likely to be mis-scoped, because the permissions are broader and the blast radius of a leaked token is every client under that agency.
state value you generated and stored against the user's session.state matches what you stored, then discard it. Skipping this check is what makes a flow vulnerable to request forgery.403 that indicates a scope you believed you had.state value.state value.Scenario: an agency installs your reporting product once at the parent level, and your product then reads opportunity data for five client sub-accounts.
state, stores it against their session, and redirects them to the platform's authorize URL with your client id, your agency-level scopes and your redirect URI.state value.state to the stored one, confirms the match, and deletes it.403 on a pipeline endpoint, which tells you that scope was never granted; you flag that account in the UI with a Reconnect to enable prompt rather than silently publishing an incomplete report.Token endpoints are rate limited like any other, and a bug that refreshes on every API call rather than on a timer will hit that limit and take your whole integration down. Refresh once per installation per window, behind a lock. API calls made with the resulting token count against the account's normal API budget, so an agency-level app serving many accounts should spread work across the window rather than firing every account's sync at midnight.
Authorization codes are single-use. Retrying a failed exchange with the same code fails, and if the first attempt actually succeeded you have just thrown away a valid token pair, so persist tokens before returning a response to the browser. Refresh tokens commonly rotate on use: if you retry a refresh with the old token after a successful rotation you will be told the grant is invalid, which looks exactly like revocation. Make refresh atomic and persist before reuse.
Scope identifiers are literal strings and are not interchangeable with endpoint names. Read and write are distinct scopes for the same resource. Store the granted scope list and check against it in code, so a missing permission surfaces as a clear error in your own logs rather than an opaque 403 in production.
Nothing stops the same account being authorized twice: a user clicks Connect again, or two team members each connect. Key your installation records on the account identifier and treat a second grant as a replacement, or you will run two syncs against one account and double-create records.
Use a separate app registration per environment, with its own client secret and its own redirect URI. Pointing a staging app at a production account is how test data ends up in a client's pipeline, and sharing one registration across environments means you cannot revoke one without breaking the other.
Access tokens expire in minutes to hours; refresh tokens last longer but are not permanent. A grant dies when the user disconnects the app, when an administrator removes the installation, when the account is closed, or when the platform invalidates it. Distinguish 401 (token expired, refresh it) from an invalid-grant error on refresh (the grant is gone, ask a human to reconnect). Looping on the second case is the most common failure mode in production.
state not validated, or validated against a cookie that was lost in a cross-site redirect.We wire the integration, map the fields, test both directions and hand it over with the SOPs your team needs to run it.
Book a call