← library
Admin-gated self-serve
Content management / cloud storage·agent-generated · deepseek-v4.1-flash·checked 2026-10-28
difficulty
3/5

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.

First working connection
~30–90 minutes
Production / approved
~1–3 days for enterprise admin approval (inferred); listing/per-customer enablement longer
Composio managed OAuth
Available: ship today
Composio lists a managed OAuth app for this toolkit — you can ship on it while your own app is set up or reviewed.
who does itagent 4you 5provider 0
evidencetested 5sourced 38inferred 5
◆ agent run11 pages read33/38 quotes verified verbatim89s$0.030deepseek-v4.1-flash

01Pick your path

Free developer account (your own content)
when Prototyping, or an agent only needed for your own Box account.
→ App is authorized automatically; you can be authenticating users the same hour.
Enterprise internal app
when Users sit inside your company's Box enterprise.
→ Blocked until a Box Admin authorizes the Client ID in the Admin Console; every scope change needs re-authorization.
Distributed / Integrations listing
when Shipping to users in other enterprises' Box accounts.
→ Each customer enterprise's admin must enable your app when unpublished apps are disabled by default; listing shows under Integrations after publishing.

02Time & effort

Hands-on work
1.1 h – 3 h
Waiting on others
2 weeks – 4 weeks
You're actually working
<1% of elapsed time
Phases
5
start↑ first working connection, then production pathproduction
  1. 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.
  2. 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.
  3. 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.
  4. 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.
  5. PRODIntegrations listing / per-customer enablementwait 2–4 weekssourced[S6][S3]Timing inferred — sources describe the Integrations listing but publish no review SLA.
agent can do it you waiting on providerbar widths ∝ √time, so short tasks stay visible

03Steps

0/9 done

Get a working connection

  1. Create a User-type Platform Appyousourced ❝[S7][S5]

    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 signup
    https://account.box.com/signup/developer
  2. Register exact redirect URIs (and CORS if browser-side)yousourced ❝[S7]

    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
  3. Enable the narrowest scopes, then downscope at authorize timeagentsourced ❝[S9]

    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
  4. Implement the authorization-code flowagentsourced ❝[S5][S11]

    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 skeleton
    import 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_token
  5. Exchange the code and handle refreshagentinferred[S11][probe]

    POST the code with the client secret to the token endpoint, store the refresh token, and treat access tokens as ~1 hour. Token response/error shapes (invalid_client) are documented under Authorization resources.

  6. Smoke-test with /users/meagentsourced ❝[S1]

    First 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

  1. Get the Client ID authorized by a Box Adminyousourced ❝[S8][S3]

    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 draft
    Subject: 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>
  2. Re-authorize after every scope changeyousourced ❝[S8][S10]

    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
  3. Optional: list in Box Integrationsyouinferred[S6][S3]

    Publishing puts you under Integrations rather than Platform Apps, and enterprise admins authorize via 'Set to available in individual app controls'. Publish only if you need cross-enterprise distribution.

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 / permissionTierNoteEvidence
root_readonlybasicRead 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_readwritesensitiveRead and write all files/folders — upload, new versions, download, folders, comments, tasks. Needed for any write action; justify explicitly.sourced ❝[S9]
manage_webhooksensitiveCreate webhooks for a user; 1,000 per app per user limit.sourced ❝[S9]
ai.readwritesensitiveSend requests to the Box AI API.sourced ❝[S9]
sign_requests.readwritesensitiveGet/create/cancel/resend Box Sign requests; auto-pulls read/write scopes and requires Sign enabled on the enterprise.sourced ❝[S9]
manage_managed_usersrestrictedManage users (login, password, roles) — the access token must belong to an Admin/Co-Admin.sourced ❝[S9]
manage_groupsrestrictedCreate/update/delete groups and memberships; admin-scoped token required.sourced ❝[S9]
manage_enterprise_propertiesrestrictedEnterprise event stream, attributes, reports, device pins, Shield lists — admin token, high blast radius.sourced ❝[S9]
manage_data_retentiongatedRetention policies; requires purchased Box Governance plus the enterprise_content scope.sourced ❝[S9]
manage_triggerssensitiveBox Relay / WORKFLOW_MANUAL_START; requires read/write scopes too.sourced ❝[S9]
Legal Holds, Suppress email notifications, Global Content Manager (GCM)gatedOnly on request via a support ticket, reviewed case by case, and unavailable on free trial accounts.sourced ❝[S9]

05If you get blocked

✕Your OAuth app is invisible to your enterprise's Admin Console, so users can't be granted access.sourced ❝[S8]

→ 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.

✕redirect_uri mismatch — strict exact match is enforced; omitting the parameter yields a redirect_uri_missing error and no redirect back.sourced ❝[S7]

→ 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.

✕You expect invalid_client from the authorize endpoint but get a 200 HTML login page instead, so a bad Client ID looks like success.inferred[probe][S11]

→ 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.

✕You need an on-request scope (legal holds, suppress email notifications, Global Content Manager) and the request is refused or ignored.sourced ❝[S9]

→ Log in to a paid enterprise account, then file the support ticket with the use case; cannot be requested on a free trial.

✕Changing scopes or access level has no effect on the running app.sourced ❝[S8]

→ 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

$ probes: live GETs with a dummy client_id, no credentials
✓ Discovery document (/.well-known/openid-configuration) → 404
https://account.box.com/.well-known/openid-configuration
not published
∴ Box is not an OIDC provider — no discovery document, so no id_token or OIDC libraries expecting openid-configuration. Use plain OAuth 2.0 authorization-code.
✓ Discovery document (/.well-known/oauth-authorization-server) → 200
https://account.box.com/.well-known/oauth-authorization-server
issuer=https://api.box.com; authorization_endpoint=https://account.box.com/api/oauth2/authorize; token_endpoint=https://api.box.com/oauth2/token; scopes_supported=n/a
∴ Same document is served on the authorize host; you can fetch metadata from either origin.
✓ Discovery document (/.well-known/openid-configuration) → 401
https://api.box.com/.well-known/openid-configuration
not published
∴ Also no OIDC discovery on the API host (401). Don't probe for it.
✓ Discovery document (/.well-known/oauth-authorization-server) → 200
https://api.box.com/.well-known/oauth-authorization-server
issuer=https://api.box.com; authorization_endpoint=https://account.box.com/api/oauth2/authorize; token_endpoint=https://api.box.com/oauth2/token; scopes_supported=n/a
∴ Machine-readable config works here: issuer https://api.box.com, authorize at account.box.com/api/oauth2/authorize, token at api.box.com/oauth2/token. scopes_supported is absent, so build no scope-discovery logic — read scopes from the console/docs.
✓ Authorize endpoint with a fake client_id → 200
https://account.box.com/api/oauth2/authorize?client_id=probe_invalid_client&response_type=code&redirect_uri=https%3A%2F%2Fexample.com%2Fcallback
text/html; charset=UTF-8 — HTML/login page
∴ A bogus client_id still returns 200 HTML (login page) — the endpoint does not reject unknown clients up front. Expect invalid_client only at the token step, so test with a real client and registered redirect URI.

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.