Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Facebook Graph Laravel Package

joelbutcher/laravel-facebook-graph

A Laravel integration for the Facebook Graph SDK, making it easy to authenticate, query the Graph API, and manage Facebook resources from your PHP applications with familiar Laravel conventions.

View on GitHub
Deep Wiki
Context7

Getting Started

joelbutcher/laravel-facebook-graph is a thin Laravel integration layer over the official facebook/graph-sdk. You get a manager class, a Facebook facade, config-driven app credentials, and Laravel-native session handling for the OAuth helpers — instead of hand-wiring Facebook\Facebook in every project.

Install and publish

composer require joelbutcher/laravel-facebook-graph
php artisan vendor:publish --tag=facebook-config   # or --provider="JoelButcher\Facebook\FacebookServiceProvider"

Package discovery registers the service provider and the Facebook facade alias, so no manual config/app.php edits are needed on modern Laravel.

Credentials in .env

FACEBOOK_APP_ID=...
FACEBOOK_APP_SECRET=...
FACEBOOK_DEFAULT_GRAPH_VERSION=v21.0
FACEBOOK_DEFAULT_ACCESS_TOKEN=      # optional, leave empty in most apps

First use case — read the authenticated user's profile with a token you already hold:

use JoelButcher\Facebook\Facades\Facebook;

$response = Facebook::get('/me?fields=id,name,email', $user->facebook_token);

return $response->getGraphUser()->asArray();

Where to look first

  1. config/facebook-graph.php — this maps almost 1:1 onto the SDK's config array (app_id, app_secret, default_graph_version, default_access_token, persistent_data_handler, http_client_handler, enable_beta_mode, enable_appsecret_proof). Nearly every "why is it doing that?" question is answered here.
  2. JoelButcher\Facebook\Facebook (the class behind the facade) — read its public methods before the SDK docs; it exposes getClient(), getOAuth2Client(), getRedirectLoginHelper(), and extend().
  3. The Facebook\ SDK classes for anything the wrapper doesn't cover. The package is deliberately thin — the escape hatch is always Facebook::getClient().

v1.5.0 only adds Laravel 12 / illuminate/* ^12.0 compatibility; there is no API change, so anything written against v1.4.x carries over unchanged.

Implementation Patterns

Inject the manager, don't reach for the facade. For anything in a service class or job, type-hint JoelButcher\Facebook\Facebook (or the manager binding) in the constructor. The facade is fine in controllers and Blade, but container injection makes the class swappable in tests.

OAuth login flow. Generate the login URL, handle the callback, then immediately upgrade the short-lived token:

$helper = Facebook::getRedirectLoginHelper();
$url    = $helper->getLoginUrl(route('facebook.callback'), ['email', 'pages_manage_posts']);

// callback
$token = $helper->getAccessToken();                       // ~1-2h token
$long  = Facebook::getOAuth2Client()->getLongLivedAccessToken($token); // ~60 days
$user->update(['facebook_token' => encrypt($long->getValue())]);

Store tokens encrypted and record the expiry (getExpiresAt()); treat anything near expiry as needing a refresh rather than discovering it via a 190 error in production.

Page tokens. The common real workflow is: user token → GET /me/accounts → store the page token and page id per tenant. Page tokens don't expire on a schedule but can be invalidated by a password change or revoked permission, so keep the user token around to re-derive them.

Multi-app / multi-tenant setups. Use Facebook::extend('tenant', fn ($app) => new Facebook([...])) and create named drivers per Facebook app rather than mutating the default config at runtime. This is also the cleanest way to separate a "marketing app" from a "login app" with different scopes.

Explicit versions per call. Pass the graph version on calls that must be pinned while you migrate between versions, rather than flipping the global default and breaking every endpoint at once.

Queue the writes. POST /me/feed, /comments, ad mutations and similar should go through jobs with backoff. Facebook rate limits are per-app and per-page, so a single retry loop in a controller will bite you at the first traffic spike.

Webhook handling is yours to write. The package gives you the client; it does not verify X-Hub-Signature-256 or handle the hub.challenge handshake. Use hash_hmac('sha256', $rawBody, config('facebook-graph.app_secret')) with hash_equals, and exclude that route from CSRF.

Testing. Bind a stub Facebook instance (or a preconfigured client with a fake access token) in the container. Because the SDK speaks to Guzzle directly rather than through Laravel's HTTP client, Http::fake() will not intercept these calls — expect to mock the manager or inject a mock Facebook\Client.

Gotchas and Tips

  • Http::fake() doesn't work. The biggest time-waster for newcomers. The SDK owns its own Guzzle instance; either mock at the manager level or supply a custom http_client_handler.
  • Graph API versions expire. Facebook retires versions after roughly two years. default_graph_version in config is a hardcoded string — put a recurring ticket on it, and expect a wave of "Unsupported get request" errors when it lapses. v1.5.0 does not change the pinned default.
  • Session dependency in OAuth helpers. The persistent data handler is session-backed, so getLoginUrl()/getAccessToken() will misbehave in stateless API routes, queue workers, and console commands. If you're doing token exchange outside a browser session, use the OAuth2Client directly instead of the redirect helper.
  • Two different exception families. Facebook\Exceptions\FacebookSDKException means you configured something wrong (bad credentials, unusable token). Facebook\Exceptions\FacebookResponseException means the Graph API returned an error. Catch them separately — the second carries getStatusCode(), getErrorCode() and getErrorSubcode(), which you need to distinguish a rate limit (codes 4/17/32) from an expired token (code 190) from a permission problem (code 200).
  • Enable app secret proof in production. enable_appsecret_proof guards against token misuse once an app has an app secret; leaving it off is a finding in most security reviews.
  • Config caching. env() values are only read at cache time. After changing FACEBOOK_*, run php artisan config:clear — otherwise you'll debug a "wrong app id" that isn't in your .env at all.
  • Laravel 12 upgrade path. v1.5.0 widens the framework constraint, nothing more. Requirements: PHP 8.2+, and confirm the facebook/graph-sdk version in composer.lock is the one the package expects (it's an abandoned package, so vendor it or pin it deliberately). Run your OAuth callback test and one authenticated get() before shipping — those are the two paths that touch the SDK's config and session handling.
  • Debugging tokens. GET /debug_token via Facebook::get('/debug_token?input_token=...') (or getOAuth2Client()->debugToken()) returns scopes, expiry, and app id — far more useful than the opaque 190 error when a token silently stops working.
  • Extension points worth knowing: Facebook::extend() for named drivers, getClient() for anything the wrapper doesn't proxy, and the http_client_handler config key when you need to swap Guzzle for a client with custom middleware (logging, retries).
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log