dcblogdev/laravel-box
Laravel Box provides a simple integration with the Box API, letting Laravel apps authenticate and manage files and folders through Box. It wraps Box SDK configuration and offers convenient access from your Laravel project.
composer require dcblogdev/laravel-box, then publish the config (and migrations, if the package ships a token table) with php artisan vendor:publish --provider="Dcblogdev\Box\BoxServiceProvider". This package is one of the dcblogdev family (Dropbox/OneDrive/Box), so the shape is familiar: a service provider, a config/box.php, an OAuth connect/callback route pair, and a Box facade.config/box.php (client ID, client secret, redirect URI, and the token storage driver), then vendor/dcblogdev/laravel-box/src/ to see the actual client classes and route names. The README gives you the OAuth dance; the source gives you the method surface, which is rarely fully documented.https://your-app.test/box/oauth/callback), and select the right app type — box's "Standard OAuth 2.0 (User Authentication)" vs "JWT" decision is made in the console, and only OAuth 2.0 user auth fits this package's flow.php artisan tinker, e.g. Box::files()->listContents('0') or Box::folders()->all(), to prove end-to-end wiring before building anything real.composer.json constraint widening for Laravel 13 only — no code changes, no API changes. If you're pinned to ^2.1.8 on Laravel 12, nothing moves until you bump Laravel. If you're moving to Laravel 13, pull ^2.1.9 in the same commit as the framework upgrade and confirm your PHP version satisfies Laravel 13's floor.Box behind a small BoxStorage / CloudStorage service (or an interface with a fake implementation) so your domain code never imports the vendor facade. This is what makes the package testable and swappable later.upload(string $path, $contents): string and download(string $id): string contract keeps your callers provider-agnostic.Box::refreshToken()-style call to a php artisan box:refresh command scheduled every ~45 minutes for single-tenant apps.Box::folders()->create(...)) as the tenant boundary — create one folder per customer/project on onboarding, store the Box folder ID on your model, and never resolve folders by name at runtime (names are not unique and are user-renamable).listContents in a loop — you'll hit rate limits fast.Http::fake() only intercepts the default Laravel HTTP client. If the package builds its own Guzzle client, fake at your own boundary (swap your BoxStorage implementation) or use a Guzzle MockHandler bound into the container.http vs https. A mismatch surfaces as a generic Box invalid_request on the callback, which looks like a code bug but is a config bug. Check APP_URL and any proxy/TrustProxies setup that rewrites the scheme..env, run php artisan config:clear; a cached config will keep sending the old client secret and Box will return invalid_client with no useful detail.{"type":"error","status":4xx,"code":"...","context_info":{...}}. The package may surface a raw response or a generic exception — log the full body, because item_name_invalid vs item_name_too_long vs conflict all look alike otherwise.Retry-After; naive retry loops make it worse. Add jittered backoff and, for bulk operations, throttle with Bus::batch()->allowFailures() plus a rate limiter.0 is root; don't treat 0 as falsy in your code (if (!$folderId) silently redirects everything to root). Cast to string and compare explicitly.^2.1 is safe and gets you Laravel 13 compatibility for free when you get there. If you're stuck on Laravel 12 for a while, there is no reason to hold back on this release.How can I help you explore Laravel packages today?