OAuth 2.0 is self-serve in your own developer account (under ~90 minutes), but reaching other enterprises' users is gated by a Box Admin authorizing your Client ID in Platform Apps Manager — and on-request scopes (legal holds, GCM) need a support ticket on a paid enterprise plan.
01Pick your path
02Time & effort
- DEVCreate User-type app in Developer Console5–15 minutessourced[S7][S5]New App > User > Create. Needs your Box login; a free developer account is enough.
- DEVConfigure redirect URIs, scopes, CORS15–45 minutessourced[S7][S9]Agent can draft the URI list, scope justification and CORS allow-list; you paste them into the Configuration tab.
- DEVImplement authorize → code → token → refresh45–120 minutessourced[S5][S11]Agent writes the flow; you supply client ID/secret placement and run the first browser consent yourself.
- PRODBox Admin authorizes the Client IDwait 1–3 dayssourced[S8][S3]Timing inferred — no duration is documented. Only applies to enterprise accounts; free developer apps are auto-authorized.
- PRODIntegrations listing / per-customer enablementwait 2–4 weekssourced[S6][S3]Timing inferred — sources describe the Integrations listing but publish no review SLA.
03Steps
Get a working connection
Log in at https://account.box.com/developers/console, then New App > User > Create. User = OAuth 2.0 on behalf of a signed-in user; the choice is irreversible.
“Once you create an OAuth 2.0 app, you cannot change it to Server Authentication (or the other way around).” — [S7] verified verbatim
↗ account.box.com/developers/console◆ prepared by agent · Free developer account signuphttps://account.box.com/signup/developer
Configuration tab > OAuth 2.0 Redirect URI. Exact-match, HTTPS (HTTP allowed only for localhost/loopback, where port may vary). Multiple URIs are allowed; duplicates are rejected. Add the CORS Domain at the bottom of the Configuration tab only if you call the API from browser JS.
“Localhost and loopback address redirect URIs will be permitted to redirect to any port, but the scheme, domain, path and query parameters must match one of the configured URIs.” — [S7] verified verbatim
Application Scopes section of Configuration: enable the minimum (root_readonly first). Then downscope per-request on the authorize URL, e.g. scope=root_readonly, so each token carries less than the app maximum.
“For example, if your application has the root_readonly and root_readwrite scopes enabled, it is possible to restrict a user’s access token to root_readonly by specifying this scope when redirecting the user.” — [S9] verified verbatim
Build the authorize URL from client ID + registered redirect URI + state; send the user to Box to log in and approve scopes; Box redirects back with a short-lived code.
“Your application builds an authorization URL from its client ID and a registered redirect URI, and sends the user to it.” — [S5] verified verbatim
◆ prepared by agent · Authorize URL + token exchange skeletonimport secrets, urllib.parse params = { "client_id": BOX_CLIENT_ID, "response_type": "code", "redirect_uri": "https://yourapp.example.com/callback", # must match console exactly "state": secrets.token_urlsafe(24), "scope": "root_readonly", # may only narrow console-enabled scopes } url = "https://account.box.com/api/oauth2/authorize?" + urllib.parse.urlencode(params) # token exchange (server-side only; keep client_secret out of the browser) # POST https://api.box.com/oauth2/token with grant_type=authorization_code, code, # client_id, client_secret -> {access_token, expires_in, refresh_token} # refresh: grant_type=refresh_tokenFirst call should be GET https://api.box.com/2.0/users/me with the bearer token to confirm identity and wiring before touching content.
“A successful response returns the user profile or app service account who the token belongs to.” — [S1] verified verbatim
↗ api.box.com/2.0/users/me
Make it production-ready
Enterprise accounts: from the Configuration tab choose 'Submit app for authorization for access to the Enterprise' (or the Enablement tab), which emails the Primary Admin. Manual route: Admin Console > Platform > Platform Apps > Add with the Client ID; with unpublished-apps-disabled settings on, the path is Integrations > Platform Apps Manager > User Authentication Apps > More > enable. Free developer accounts are auto-authorized.
“Submitting the application for approval sends an email to your enterprise’s Primary Admin to approve the application.” — [S8] verified verbatim
◆ prepared by agent · Admin authorization request draftSubject: Authorize Box OAuth app <APP NAME> (Client ID: <CLIENT_ID>) Hi <Admin>, I've built an internal integration on Box Platform using OAuth 2.0 (User authentication). It only acts on behalf of users who explicitly consent, and requests these scopes: - root_readonly — read the files/folders of the signed-in user (needed to: <one line>) - <scope> — <one line justification> Could you authorize it? Two options: 1) I've submitted it from the Developer Console; you'll get an email prompt to approve. 2) Manual: Admin Console > Platform > Platform Apps > Add, then paste Client ID <CLIENT_ID>. If our enterprise has 'Disable unpublished apps by default' enabled, it must also be enabled under Integrations > Platform Apps Manager > User Authentication Apps. Thanks, <you>
Any scope or access-level change requires re-authorization, and existing tokens won't carry the new access — plan a token re-issue in your rollout.
“When an application’s scopes or access level change, the application must be re-authorized for the changes to take effect.” — [S8] verified verbatim
04Requirements, scopes & nuances
You'll need
- ▸A Box account with Developer Console access — a free developer account qualifies; signup at https://account.box.com/signup/developer. sourced ❝[S7][S5]
- ▸Client ID plus client secret from the app's Configuration tab (secret stays server-side; the code-to-token exchange needs it). inferred[S5][S7]
- ▸At least one registered redirect URI: HTTPS, exact match required; plain HTTP only for localhost/loopback, where any port is allowed. sourced ❝[S7]
- ▸App-type decision made up front (User for OAuth 2.0) — it cannot be changed after creation. sourced ❝[S7]
- ▸For enterprise use: a Box Admin or Co-Admin holding your Client ID. If unknown, the Admin Contact is shown at the bottom of Box Account Settings. sourced ❝[S8]
- ▸A paid enterprise account if you ever need on-request scopes — requests cannot be filed from a free trial. sourced ❝[S9]
Gotchas
- !App type is permanent: a User (OAuth 2.0) app can never be converted to Server auth (JWT/CCG) — you must create a new app. sourced ❝[S7]
- !The scope query parameter can only narrow what the console already enabled — it cannot grant a scope the app doesn't have. sourced ❝[S9]
- !Scopes are a ceiling, not a grant: the signed-in user's own Box permissions must also allow each call, so an agent acting for a low-privilege user will get 403s with valid scopes. sourced ❝[S9]
- !Enterprise settings decide whether unpublished OAuth apps are usable at all: with 'Disable unpublished apps by default' on, an admin must enable the app in Integrations > Platform Apps Manager > User Authentication Apps before any user can consent. sourced ❝[S3][S8]
- !Scope bundles pull in extras: sign_requests.readwrite and manage_triggers auto-select read/write scopes, widening what you must justify. sourced ❝[S9]
- !Webhooks cap at 1,000 per application per user — relevant if your agent subscribes per-user. sourced ❝[S9]
- !Access tokens are short-lived (expires_in ~3600s in the documented example); your agent must persist and rotate refresh tokens, and re-consent after scope re-authorization. inferred[probe][S11]
| Scope / permission | Tier | Note | Evidence |
|---|---|---|---|
| root_readonly | basic | Read all files and folders for the signed-in user; still bounded by that user's own permissions. Good default for a read/answer agent. | sourced ❝[S9] |
| root_readwrite | sensitive | Read and write all files/folders — upload, new versions, download, folders, comments, tasks. Needed for any write action; justify explicitly. | sourced ❝[S9] |
| manage_webhook | sensitive | Create webhooks for a user; 1,000 per app per user limit. | sourced ❝[S9] |
| ai.readwrite | sensitive | Send requests to the Box AI API. | sourced ❝[S9] |
| sign_requests.readwrite | sensitive | Get/create/cancel/resend Box Sign requests; auto-pulls read/write scopes and requires Sign enabled on the enterprise. | sourced ❝[S9] |
| manage_managed_users | restricted | Manage users (login, password, roles) — the access token must belong to an Admin/Co-Admin. | sourced ❝[S9] |
| manage_groups | restricted | Create/update/delete groups and memberships; admin-scoped token required. | sourced ❝[S9] |
| manage_enterprise_properties | restricted | Enterprise event stream, attributes, reports, device pins, Shield lists — admin token, high blast radius. | sourced ❝[S9] |
| manage_data_retention | gated | Retention policies; requires purchased Box Governance plus the enterprise_content scope. | sourced ❝[S9] |
| manage_triggers | sensitive | Box Relay / WORKFLOW_MANUAL_START; requires read/write scopes too. | sourced ❝[S9] |
| Legal Holds, Suppress email notifications, Global Content Manager (GCM) | gated | Only on request via a support ticket, reviewed case by case, and unavailable on free trial accounts. | sourced ❝[S9] |
05If you get blocked
→ Copy the Client ID from Configuration > OAuth 2.0 Credentials (or hover the app in My Platform Apps) and send it to your Box Admin; they can also add it in Admin Console > Platform > Platform Apps > Add.
→ Register the exact production URI (scheme, host, path, query) in Configuration > OAuth 2.0 Redirect URI and always send redirect_uri on the authorize call; loopback may vary port only.
→ Never rely on the authorize response to validate config; walk the full flow in a browser with a real client and a registered redirect URI, and handle the OAuth 2.0 error object at token exchange.
→ Log in to a paid enterprise account, then file the support ticket with the use case; cannot be requested on a free trial.
→ Re-submit for authorization from Configuration and re-issue tokens; expect tokens minted before the change to lack the new access.
06Evidence: what was tested, sourced, and still uncertain
Sources read
- [S1] API Reference - Box Dev Docs official
- [S2] Using Box for Google Workspace Add-on official
- [S3] Authorization - Box Dev Docs official
- [S4] Applications - Box Dev Docs official
- [S5] OAuth 2.0 authentication - Box Dev Docs official
- [S6] Platform Apps - Box Dev Docs official
- [S7] Setup with OAuth 2.0 - Box Dev Docs official
- [S8] Platform app approval - Box Dev Docs official
- [S9] Box API scopes - Box Dev Docs official
- [S10] Limited Access App Approval - Box Dev Docs official
- [S11] Authorization resources - Box Dev Docs official
- [composio] Composio — Managed OAuth apps directory official
- [probe] Live HTTP probes run by the agent (dummy client_id, no credentials) probe
Still uncertain
- ? No source states approval durations. The 1–3 day admin wait and 2–4 week listing estimate are inferred; Box only says apps 'may require approval'.
- ? Sources don't document the exact token-exchange request shape (body vs Basic auth for client credentials) or token/refresh lifetime beyond an expires_in of 3600 in an example — confirm at developer.box.com before shipping.
- ? Whether publishing to Box Integrations has a formal review/SLA is not covered; [S6] only mentions listing and the approval guide covers admin authorization, not a marketplace review.
- ? Scope-to-endpoint mapping is coarse: scopes are file/folder-wide (root_readonly/root_readwrite), so a least-privilege agent still gets whole-account read/write on consent — downscoping to a single item relies on the token's restricted_to/access-token downscoping behaviour, which the fetched sources only sketch.
- ? Rate limits and webhook reliability details were not fetched.
- ? No source confirms behaviour of per-customer enterprise enablement at scale (the 10,000 authorized-app cap per enterprise was fetched, but not tenant onboarding UX).
- ? Generated automatically; no app was registered and no review was submitted.