Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.mirage.strukto.ai/llms.txt

Use this file to discover all available pages before exploring further.

Overview

The Box resource uses OAuth2 against the Box v2 API to:
  • /folders/{id}/items, list folder items (root id is 0)
  • /files/{id}/content, download file bytes
  • /files/{id} / /folders/{id}, fetch entry metadata
  • /search, search files by name/content
  • /oauth2/token, refresh access tokens
Box is similar to Dropbox in shape but uses numeric folder/file IDs rather than paths. Mirage caches the path → ID mapping in the index store, so once you ls /box/ the IDs are remembered and subsequent reads don’t pay the lookup cost. Three credential modes are supported:
  • Developer token, fastest first-run path. Click one button in the Box app console, paste the 32-char access token, and you’re done. Lives 60 minutes; you regenerate by hand. No client_id / refresh_token / OAuth flow needed. Recommended for mirage exploration.
  • Code flow with client secret, for Node/server long-running use. Needs client_id, client_secret, refresh_token.
  • PKCE flow, for browsers. Needs only client_id and refresh_token (no secret in the bundle).
Box rotates the refresh token on every refresh. The token you copy out of the initial code exchange is only valid until the next refresh, after that, only the new rotated token works. The BoxTokenManager keeps the latest token in memory; pass onRefreshTokenRotated if you want to persist it across restarts (the browser example does this with localStorage).

Quick Start: Developer Token (60 minutes, no OAuth)

If you just want to try the resource against your own Box account, the developer token is the fastest path, no redirect URI, no client secret, no curl exchange:
  1. Go to https://app.box.com/developers/console -> Create New App -> Custom App -> User Authentication (OAuth 2.0) -> name it “Mirage” -> Create App
  2. On the Configuration tab, scroll to the Developer Token section near the bottom.
  3. Click Generate Developer Token. Copy the 32-char token.
  4. Paste into your .env.development:
    BOX_DEVELOPER_TOKEN=...
    
  5. Run any of the examples in examples/typescript/box/.
The token expires in 60 minutes and there is no programmatic way to renew it; you regenerate by hand. For long-running processes, use the OAuth flow below instead. When BOX_DEVELOPER_TOKEN is set, the BoxResource skips the OAuth refresh path entirely and calls Box directly with the token in the Authorization: Bearer header.

Setup (long-running OAuth flow)

1. Create a Box App

  1. Go to https://app.box.com/developers/console
  2. Click Create New App
  3. Choose Custom App
  4. Authentication Method: User Authentication (OAuth 2.0)
  5. Name it (e.g. “Mirage”) -> Create App

2. Configure the App

Open the app’s Configuration tab:
  • OAuth 2.0 Redirect URIs: add every destination you’ll redirect back to. Box accepts multiple values, register them all up front so you don’t bounce between dev and prod:
    • For the CLI flow below: http://localhost:1
    • For the browser PKCE example: http://localhost:5173/box_pkce.html
    • For production: e.g. https://yourapp.com/box/callback
  • Allowed Origins (only needed if you’ll call from a browser; older Box docs call this “CORS Domains”):
    • http://localhost:5173
    • Any production origins (e.g. https://yourapp.com)
  • Application Scopes:
    • Read all files and folders stored in Box (required)
    • Write all files and folders stored in Box (only if you’ll add write commands later)
  • Click Save Changes

3. Submit for Authorization (enterprise apps only)

If your Box account is part of an enterprise, the Authorization tab requires an admin to approve the app before it can issue tokens. Personal/free Box accounts skip this step.

4. Copy the Client Credentials

Still on Configuration, copy:
  • Client ID -> BOX_CLIENT_ID
  • Client Secret -> BOX_CLIENT_SECRET (skip if you only need PKCE)

5. Get the Refresh Token (CLI flow with client secret)

A) Open this URL in a browser (replace YOUR_CLIENT_ID):
https://account.box.com/api/oauth2/authorize?response_type=code&client_id=YOUR_CLIENT_ID&redirect_uri=http://localhost:1
B) Authorize: sign in -> click Grant access. C) Copy the code: browser redirects to http://localhost:1?code=... (page won’t load, expected). Copy the code from the URL bar. D) Exchange the code:
curl https://api.box.com/oauth2/token \
  -d "code=THE_CODE" \
  -d "grant_type=authorization_code" \
  -d "client_id=YOUR_CLIENT_ID" \
  -d "client_secret=YOUR_CLIENT_SECRET" \
  -d "redirect_uri=http://localhost:1"
Response shape:
{
  "access_token": "T...",
  "expires_in": 3884,
  "refresh_token": "R...",
  "restricted_to": [],
  "token_type": "bearer"
}
Save the refresh_token.

6. Set Environment Variables

# .env.development
BOX_CLIENT_ID=...
BOX_CLIENT_SECRET=...
BOX_REFRESH_TOKEN=...

Alternative: PKCE Flow (browser, no client secret)

  1. Add http://localhost:5173/box_pkce.html to OAuth 2.0 Redirect URIs
  2. Add http://localhost:5173 to Allowed Origins
  3. Set only BOX_CLIENT_ID in .env.development
  4. From examples/typescript/browser/, run pnpm dev
  5. Open http://localhost:5173/box_pkce.html and click Connect Box
The example persists the rotated refresh token to localStorage via the onRefreshTokenRotated callback so subsequent page loads work without re-auth.

Token Lifetime

TokenLifetime
Access token~1 hour (expires_in: ~3600)
Refresh token60 days from issue, OR 60 days from last use (whichever)
A refresh token gets revoked when:
  • 60 days pass without use
  • The user revokes the app at https://app.box.com/account/security
  • The Box account password changes
  • A new refresh token is issued (the old one expires after a short grace period)
The BoxTokenManager always uses the latest token. For long-running processes restart-safe, provide onRefreshTokenRotated to persist the new token to disk / a vault.

CORS Notes

Unlike Dropbox, Box has first-class CORS but only for origins you’ve explicitly allowlisted in the Allowed Origins section of the app configuration. If you see browser-side Access-Control-Allow-Origin errors, double-check the origin matches exactly (no trailing slash; protocol matters).

Troubleshooting

IssueFix
400 invalid_grant on token exchangeThe code is single-use and short-lived, redo Step 5A with a fresh URL
403 access_deniedEnterprise admin hasn’t approved the app on the Authorization tab
401 unauthorized after a few hoursRefresh token rotation, the original token is invalid; persist via onRefreshTokenRotated
Browser: CORS error even though origin setCheck that the origin in Allowed Origins is exact (no trailing slash, http vs https)
path/not_found on ls /box/<folder>/The folder name was constructed wrong, use ls /box/ first, then drill into a name from the list
For TypeScript usage:
import { BoxResource } from '@struktoai/mirage-node'

const box = new BoxResource({
  clientId: process.env.BOX_CLIENT_ID!,
  clientSecret: process.env.BOX_CLIENT_SECRET!,
  refreshToken: process.env.BOX_REFRESH_TOKEN!,
})
Or browser (PKCE):
import { BoxResource } from '@struktoai/mirage-browser'

const box = new BoxResource({
  clientId: 'YOUR_CLIENT_ID',
  refreshToken: refreshTokenFromLocalStorage,
  onRefreshTokenRotated: (next) => localStorage.setItem('box-refresh', next),
})