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 Sdk Laravel Package

sammyk/laravel-facebook-sdk

sammyk/laravel-facebook-sdk wraps the official Facebook PHP SDK for Laravel, providing a convenient facade, configuration, and dependency injection. It simplifies Facebook login, access token handling, and Graph API requests in your Laravel applications.

View on GitHub
Deep Wiki
Context7

Getting Started

Reality check first: the repository is archived and facebook/graph-sdk (v5) is abandoned. Before you invest, confirm you're on Laravel 5.x/6-ish — Composer constraints on illuminate/support and Guzzle will usually block installs on Laravel 8+ anyway. On anything modern, skip the package and call https://graph.facebook.com/{version}/... directly with Http:: — the day-to-day API surface you actually use is about five endpoints.

If you're on a compatible stack:

composer require sammyk/laravel-facebook-sdk
php artisan vendor:publish --provider="SammyK\LaravelFacebookSdk\LaravelFacebookSdkServiceProvider"

Laravel 5.5+ auto-discovers the provider and the Facebook facade alias. On older versions add to config/app.php:

SammyK\LaravelFacebookSdk\LaravelFacebookSdkServiceProvider::class,
// aliases
'Facebook' => SammyK\LaravelFacebookSdk\FacebookFacade::class,

Then set in .env:

FACEBOOK_APP_ID=...
FACEBOOK_APP_SECRET=...
FACEBOOK_DEFAULT_GRAPH_VERSION=v2.5

Look at these three things, in this order:

  1. config/laravel-facebook-sdk.php — every behaviour (graph version, persistence, HTTP handler, beta mode) is decided here.
  2. src/LaravelFacebookSdk.php — it's a thin wrapper, roughly 300 lines. Read it once; it removes all mystery about what the facade does versus the underlying Facebook\Facebook.
  3. The README's login example — that's the 80% use case.

First use case — Facebook Login + one API call. Two routes:

// routes/web.php — must be inside the 'web' middleware group
Route::get('auth/facebook', function () {
    // v3 signature is (callbackUrl, scopes); v1/v2 swapped these.
    // Check the README for your pinned version before copying.
    return redirect(Facebook::getLoginUrl(route('fb.callback'), ['email', 'public_profile']));
})->name('fb.login');

Route::get('auth/facebook/callback', function () {
    try {
        $token = Facebook::getAccessTokenFromRedirect(route('fb.callback'));
    } catch (\Facebook\Exceptions\FacebookSDKException $e) {
        return redirect('/')->withErrors($e->getMessage());
    }

    Facebook::setDefaultAccessToken($token);

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

    auth()->login($userRecord = User::updateOrCreate(
        ['facebook_id' => $user['id']],
        ['name' => $user['name'], 'email' => $user['email'] ?? null, 'fb_token' => (string) $token]
    ));

    return redirect('/dashboard');
})->name('fb.callback');

That's the whole package in one screen: build a login URL, exchange the code for a token, set it as default, make Graph calls.

Implementation Patterns

Wrap the facade in your own service. The facade is a singleton with mutable state (setDefaultAccessToken), which makes it awkward in tests and dangerous in long-lived processes. Inject SammyK\LaravelFacebookSdk\LaravelFacebookSdk into a FacebookService and let callers deal in your domain objects, not GraphNodes.

class FacebookService
{
    public function __construct(private LaravelFacebookSdk $fb) {}

    public function profile(AccessToken $token): array
    {
        $node = $this->fb->get('/me?fields=id,name,email,picture.width(200)', [], $token)
                        ->getGraphUser();

        return ['id' => $node['id'], 'name' => $node['name'], 'avatar' => $node['picture']['url'] ?? null];
    }
}

Note the third argument: get(), post(), delete(), and sendRequest() all accept an explicit token, so you can avoid setDefaultAccessToken() entirely — that's the single biggest code-quality win with this package.

Token lifecycle. Short-lived user tokens die in ~1–2 hours. On callback, immediately exchange for a long-lived one (~60 days) and persist it:

$short   = Facebook::getAccessTokenFromRedirect(route('fb.callback'));
$longLived = Facebook::getLongLivedAccessToken($short); // returns AccessToken
$user->update([
    'fb_token'            => (string) $longLived,
    'fb_token_expires_at' => $longLived->getExpiresAt()?->format('Y-m-d H:i:s'),
]);

For app-scoped or page-scoped jobs use Facebook::getAppAccessToken() (good for /app, webhook subscriptions, debugging) or fetch a page token once and store it — page tokens obtained from a long-lived user token generally don't expire.

Pagination. Graph returns edges; the SDK handles cursors:

$response = Facebook::get('/me/feed', ['limit' => 50], $token);
$edge = $response->getGraphEdge();

do {
    foreach ($edge as $post) { /* ... */ }
} while ($edge = Facebook::getFacebook()->next($edge)); // underlying SDK

Batches. When hydrating a feed (post + likes + comments), batch instead of N calls — this is the main reason to keep the SDK rather than raw HTTP:

$batch = [
    'post'     => Facebook::getFacebook()->request('GET', '/'.$id.'?fields=message,created_time'),
    'likes'    => Facebook::getFacebook()->request('GET', '/'.$id.'/likes?summary=true'),
    'comments' => Facebook::getFacebook()->request('GET', '/'.$id.'/comments?limit=10'),
];
$responses = Facebook::getFacebook()->sendBatchRequest($batch, $token);

getFacebook() is the escape hatch to the full v5 SDK — use it whenever the wrapper is too narrow.

Observability via events. The package fires FacebookResponseEvent, FacebookResponseErrorEvent, and FacebookResponseExceptionEvent. One listener that logs method, path, graph version, and error subcode will save you hours; register it in EventServiceProvider and you get a free audit trail for every call.

Queue jobs. Never rely on the session-held token inside a job. Load the token from your users table, pass it into the call explicitly, and catch FacebookResponseException — a revoked token in a nightly sync otherwise fails silently for weeks.

Webhooks. The package does not help here. Verify manually and compare against the app secret, then return the challenge:

abort_unless(hash_equals(
    'sha1='.hash_hmac('sha1', $request->getContent(), config('laravel-facebook-sdk.app_secret')),
    $request->header('X-Hub-Signature')
), 403);

Testing. Swap the facade (Facebook::shouldReceive('get')->andReturn($fakeResponse)) for unit tests, or, for integration-ish tests, override http_client_handler with a Guzzle MockHandler so real SDK serialization and error mapping run against recorded payloads. Bind your FacebookService with a fake in the container and you never touch the network in CI.

Gotchas and Tips

  • persistent_data_handler must not be memory for the redirect flow. The default memory handler throws away the OAuth state between the login redirect and the callback, producing FacebookSDKException: Cross-site request forgery validation failed. Set it to session (requires the web middleware group and a real session driver) or LaravelCache for stateless/API setups.
  • Session and callback must share a domain and cookie. Mixing www. and apex domains, or terminating TLS in front of a proxy with mismatched APP_URL, silently breaks state validation. Same for the OAuth redirect URI registered in the Facebook app dashboard — it must match route('fb.callback') character for character, including trailing slash.
  • The pinned Graph version is long dead. default_graph_version defaults to something like v2.5; calls will fail with unsupported-version errors. Bump the config value to a version Facebook still serves, then re-test every endpoint — the SDK's field assumptions (e.g. /me returning only id,name) and response shapes around pagination changed across versions. This is the highest-risk edit you'll make.
  • /me returns almost nothing by default. You get id and name. Always pass explicit ?fields=; if you need email you must have requested the email scope and the user must have a confirmed email — plenty of accounts return it as null.
  • Config caching. php artisan config:cache bakes in FACEBOOK_APP_SECRET. Rotating secrets in production without re-caching gives you Invalid appsecret_proof and hours of confusion. Lumen additionally needs $app->configure('laravel-facebook-sdk') and $app->withFacades().
  • Composer conflicts are the usual install failure, not your code: facebook/graph-sdk pins Guzzle 5/6 and illuminate/support to old majors. If composer require won't resolve, that's the message — don't fight it with --ignore-platform-reqs.
  • http_client_handler is your extension point. Set it to a custom Guzzle client with retry middleware, a proxy, or a logger. stream works everywhere; curl needs ext-curl and is faster under load.
  • Enable app secret proof for server-side calls (Facebook::enableAppSecretProof()); it's on by default in recent SDKs but confirm — it's cheap protection against token replay.
  • Error taxonomy matters. Catch Facebook\Exceptions\FacebookResponseException and branch on getCode()/subcode: 190 = dead/revoked token → mark the user record and re-auth; 4/17/32/613 = rate limit → exponential backoff, not retry-immediately; 100 = bad field or permission → your bug. Let FacebookSDKException (transport/config) bubble to your generic handler.
  • Debugging tip: call getFacebook()->setDefaultAccessToken(...) then replay the exact URL in the Graph API Explorer. If Explorer works and your app doesn't, the difference is almost always the token's scopes or the graph version in config.
  • Don't call getLoginUrl() in a queue or console context — it derives state/session data and will behave unpredictably without a request.
  • Migration note: since the package is archived, plan an exit. The seam is your FacebookService; replace its internals with Http::withToken($token)->get("https://graph.facebook.com/v20.0/...") and you can drop both dependencies without touching callers. Keep response mapping in that class and the swap is a day's work.
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.
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect
youbar/easy-crud
c-point-labs/laravel-hostyourai
dbravoan/dbcms-admin-theme-dbcms
dbravoan/dbcms-theme-db-cyber
dbravoan/dbcms-blocks-basic
dbravoan/dbcms-module-content-audit
dbravoan/dbcms-module-ai-assistant
paygate-to/paygate-php
padosoft/askmydocs-connector-base
defstudio/supercharged-carbon
bernskioldmedia/laravel-matomo