# Box.com Storage Integration
Complete guide for Box.com OAuth 2.0 cloud storage integration with automatic token management and file streaming.
## 📋 Table of Contents
- [Features](#features)
- [Setup Guide](#setup-guide)
- [Configuration](#configuration)
- [API Endpoints](#api-endpoints)
- [Usage Examples](#usage-examples)
- [File Type Support](#file-type-support)
- [Troubleshooting](#troubleshooting)
---
## ✨ Features
- ✅ OAuth 2.0 User Authentication
- ✅ Automatic token refresh and persistence (box-tokens.json)
- ✅ File upload with automatic folder routing (IMAGE/VIDEO/DOCUMENT)
- ✅ File streaming through your server (supports images, videos, PDFs, audio, etc.)
- ✅ File deletion by ID
- ✅ No manual token management required
---
## 🚀 Setup Guide
### Step 1: Create a Box Custom App
1. Go to [Box Developer Console](https://app.box.com/developers/console)
2. Click **"Create New App"**
3. Select **"Custom App"**
4. Choose **"User Authentication (OAuth 2.0)"** ⚠️ (NOT JWT or Client Credentials)
5. Name your app (e.g., "Streamflix API")
### Step 2: Configure OAuth Settings
1. In your app's **Configuration** tab:
- Copy **Client ID** and **Client Secret**
- Add redirect URI: `http://localhost:5119/box/oauth/callback`
- Enable scopes:
- ✅ Read all files and folders
- ✅ Write all files and folders
- Save changes
### Step 3: Get Folder IDs
1. Log in to [Box.com](https://app.box.com)
2. Create your folder structure:
```
Streamflix/
├── images/
├── videos/
└── documents/
```
3. Open each folder and copy the ID from the URL:
```
https://app.box.com/folder/358198319436
^^^^^^^^^^^^
This is the folder ID
```
### Step 4: Configure Environment Variables
Update your `.env` file:
```env
# Box.com OAuth 2.0 Configuration
BOX_CLIENT_ID="your_client_id_here"
BOX_CLIENT_SECRET="your_client_secret_here"
BOX_REDIRECT_URI="http://localhost:5119/box/oauth/callback"
# Box Folder IDs (get from Box.com URLs)
BOX_STREAMFLIX_FOLDER_ID="358198319436" # Main folder
BOX_IMAGES_FOLDER_ID="358199056099" # For IMAGE type uploads
BOX_VIDEOS_FOLDER_ID="358199692412" # For VIDEO type uploads
BOX_DOCUMENTS_FOLDER_ID="358199056099" # For DOCUMENT type uploads
# App URL (for generating content URLs)
APP_URL="http://localhost:5119"
```
### Step 5: Authorize Your Application (One-Time)
1. Start your application:
```bash
npm run start:dev
```
2. Visit the authorization URL in your browser:
```
http://localhost:5119/box/oauth/authorize
```
3. Log in to Box.com and grant access
4. **Done!** Tokens are automatically saved to `box-tokens.json`
---
## ⚙️ Configuration
### Automatic Token Management
- Tokens are stored in `box-tokens.json` (already in `.gitignore`)
- Access tokens automatically refresh every ~1 hour
- Refresh tokens are automatically updated when Box issues new ones
- No manual intervention required after initial authorization
### Folder Routing
When uploading files, specify the `fileType` parameter:
- `fileType=IMAGE` → Uploads to `BOX_IMAGES_FOLDER_ID`
- `fileType=VIDEO` → Uploads to `BOX_VIDEOS_FOLDER_ID`
- `fileType=DOCUMENT` → Uploads to `BOX_DOCUMENTS_FOLDER_ID`
- No parameter → Uploads to `BOX_STREAMFLIX_FOLDER_ID` (main folder)
---
## 📡 API Endpoints
### 1. OAuth Authorization
**Start OAuth Flow**
```
GET /box/oauth/authorize
```
Redirects to Box.com for user authorization (one-time setup).
**OAuth Callback** (Automatically called by Box)
```
GET /box/oauth/callback?code={code}
```
Exchanges authorization code for tokens and saves to `box-tokens.json`.
---
### 2. Upload File
```
POST /box/upload
```
**Query Parameters:**
- `fileType` (optional): `IMAGE`, `VIDEO`, or `DOCUMENT`
- `customFilename` (optional): Custom filename without extension
**Form Data:**
- `file`: Binary file data
**Example Request:**
```bash
curl -X POST "http://localhost:5119/box/upload?fileType=IMAGE" \
-F "file=@photo.jpg"
```
**Response:**
```json
{
"success": true,
"name": "1766841360028-photo.jpg",
"boxFileId": "2087753948639",
"size": 357909,
"folderId": "358199056099",
"publicUrl": "https://app.box.com/s/xxxxx",
"contentUrl": "http://localhost:5119/box/file/2087753948639",
"extraData": {
"sha1": "22a487ac758861029dfa5791d94c8d50c51b909e",
"createdAt": "2025-12-27T05:16:01-08:00",
"modifiedAt": "2025-12-27T05:16:01-08:00"
}
}
```
**Use `contentUrl` for direct file access!**
---
### 3. Stream File Content
```
GET /box/file/:fileId
```
Streams file content through your server. Works for images, videos, PDFs, audio, and more.
**Example:**
```html
```
**Supported Features:**
- ✅ Images display inline
- ✅ Videos support seeking (Accept-Ranges header)
- ✅ PDFs display in browser
- ✅ Audio files play inline
- ✅ Text files display inline
- ✅ Cached for 1 year (optimal performance)
---
### 4. Delete File
```
DELETE /box/by-id?fileId={fileId}
```
**Query Parameters:**
- `fileId` (required): Box file ID
**Example:**
```bash
curl -X DELETE "http://localhost:5119/box/by-id?fileId=2087753948639"
```
**Response:**
```json
{
"message": "File deleted successfully",
"success": true,
"deletedFileId": "2087753948639"
}
```
---
## 🎯 Usage Examples
### Upload and Display Image
```javascript
// Upload
const formData = new FormData();
formData.append('file', imageFile);
const response = await fetch(
'http://localhost:5119/box/upload?fileType=IMAGE',
{
method: 'POST',
body: formData,
},
);
const data = await response.json();
// Display using contentUrl
const img = document.createElement('img');
img.src = data.contentUrl; // http://localhost:5119/box/file/2087753948639
document.body.appendChild(img);
```
### Upload and Play Video
```javascript
// Upload
const formData = new FormData();
formData.append('file', videoFile);
const response = await fetch(
'http://localhost:5119/box/upload?fileType=VIDEO',
{
method: 'POST',
body: formData,
},
);
const data = await response.json();
// Play video
const video = document.createElement('video');
video.src = data.contentUrl;
video.controls = true;
document.body.appendChild(video);
```
### Delete File
```javascript
const fileId = '2087753948639';
await fetch(`http://localhost:5119/box/by-id?fileId=${fileId}`, {
method: 'DELETE',
});
```
---
## 🎨 File Type Support
### Images (Display Inline)
- JPG/JPEG, PNG, GIF, WebP, SVG, BMP, ICO, TIFF
### Videos (Play Inline with Seeking)
- MP4, WebM, OGG, AVI, MOV, WMV, FLV, MKV, M4V, 3GP
### Audio (Play Inline)
- MP3, WAV, OGG, M4A, AAC, FLAC
### Documents (Display Inline)
- PDF (viewable in browser)
- Word, Excel, PowerPoint (will download)
### Text (Display Inline)
- TXT, HTML, CSS, JS, JSON, XML, CSV, Markdown
### Archives (Download)
- ZIP, RAR, 7Z, TAR, GZ
---
## 🔧 Troubleshooting
### "No tokens found! Please authorize via OAuth"
**Solution:** Run the OAuth flow once:
```
http://localhost:5119/box/oauth/authorize
```
---
### "Refresh token expired!"
**Solution:** The refresh token has expired. Re-authorize:
```
http://localhost:5119/box/oauth/authorize
```
---
### "Box OAuth credentials not configured"
**Solution:** Check your `.env` file:
- `BOX_CLIENT_ID` must be set
- `BOX_CLIENT_SECRET` must be set
- Restart your application after updating `.env`
---
### File downloads instead of displaying inline
**Cause:** Incorrect MIME type or Content-Disposition header
**Solution:** Already fixed! The stream endpoint now:
- Detects MIME types from file extensions
- Sets `Content-Disposition: inline`
- Supports 50+ file formats
---
### Video won't seek/skip
**Cause:** Missing `Accept-Ranges` header
**Solution:** Already fixed! The stream endpoint now includes:
```
Accept-Ranges: bytes
```
This enables video seeking in all browsers.
---
### Images are resized/compressed
**Answer:** No! Files are streamed **byte-for-byte** from Box.com with no modifications. What you upload is exactly what gets delivered.
---
## 🔐 Security Notes
1. **Never commit `box-tokens.json`** - Already in `.gitignore`
2. **Keep `.env` secure** - Never commit to version control
3. **Use environment variables** in production
4. **Rotate tokens** if compromised (re-run OAuth flow)
---
## 📝 Technical Details
### Token Flow
1. **Initial Authorization** (one-time)
- User visits `/box/oauth/authorize`
- Redirected to Box.com
- User grants access
- Tokens saved to `box-tokens.json`
2. **Automatic Refresh** (background)
- Access token expires after 60 minutes
- Service automatically refreshes using refresh token
- New tokens saved to `box-tokens.json`
- If Box issues new refresh token, it's automatically updated
3. **Persistence**
- Tokens survive application restarts
- Loaded from `box-tokens.json` on startup
- No manual intervention required
### File Streaming
- Files are **streamed**, not downloaded to server
- Zero server storage used
- Supports large files (videos, archives)
- Browser caching enabled for optimal performance
- Range requests supported for video seeking
---
## 📚 Additional Resources
- [Box API Documentation](https://developer.box.com/reference/)
- [Box OAuth 2.0 Guide](https://developer.box.com/guides/authentication/oauth2/)
- [Box Developer Console](https://app.box.com/developers/console)
---
## 🎉 Quick Start Checklist
- [ ] Create Box Custom App with OAuth 2.0
- [ ] Get Client ID and Client Secret
- [ ] Create folder structure in Box.com
- [ ] Get folder IDs from URLs
- [ ] Update `.env` file
- [ ] Start application
- [ ] Visit `/box/oauth/authorize`
- [ ] Grant access to Box
- [ ] Test upload: `POST /box/upload`
- [ ] Test display: Use `contentUrl` in browser
- [ ] Done! 🚀
---
**Need help?** Check the troubleshooting section or contact support.