Fully unit tested Facebook SDK v5 integration for Laravel & Lumen

Overview

Laravel Facebook SDK

Build Status Latest Stable Version Total Downloads License

A fully unit-tested package for easily integrating the Facebook SDK v5 into Laravel and Lumen 5.0, 5.1, 5.2, & 5.3.


This is package for Laravel and Lumen 5.0, 5.1, 5.2, & 5.3

Laravel 5

Lumen 5


Shouldn't I just use Laravel Socialite?

Laravel 5 comes with support for Socialite which allows you to authenticate with OAuth 2.0 providers. Facebook Login uses OAuth 2.0 and therefore Socialite supports Facebook Login.

If all you need is to authenticate an app and grab a user access token to pull basic data on a user, then Socialite or The PHP League's Facebook OAuth Client should suffice for your needs.

But if you need any of the following features, you'll want to tie in the Facebook PHP SDK with this package:

Installation

Add the Laravel Facebook SDK package to your composer.json file.

composer require sammyk/laravel-facebook-sdk

Auto-discovery: As of version 3.5.0, the Laravel Facebook SDK supports auto-discovery for Laravel 5.5 and greater.

Service Provider

In your app config, add the LaravelFacebookSdkServiceProvider to the providers array.

'providers' => [
    SammyK\LaravelFacebookSdk\LaravelFacebookSdkServiceProvider::class,
    ];

For Lumen, add the provider to your bootstrap/app.php file.

$app->register(SammyK\LaravelFacebookSdk\LaravelFacebookSdkServiceProvider::class);

Facade (optional)

If you want to make use of the facade, add it to the aliases array in your app config.

'aliases' => [
    'Facebook' => SammyK\LaravelFacebookSdk\FacebookFacade::class,
    ];

But there are much better ways to use this package that don't use facades.

IoC container

The IoC container will automatically resolve the LaravelFacebookSdk dependencies for you. You can grab an instance of LaravelFacebookSdk from the IoC container in a number of ways.

// Directly from the IoC
$fb = App::make('SammyK\LaravelFacebookSdk\LaravelFacebookSdk');
// Or in PHP >= 5.5
$fb = app(SammyK\LaravelFacebookSdk\LaravelFacebookSdk::class);

// From a constructor
class FooClass {
    public function __construct(SammyK\LaravelFacebookSdk\LaravelFacebookSdk $fb) {
       // . . .
    }
}

// From a method
class BarClass {
    public function barMethod(SammyK\LaravelFacebookSdk\LaravelFacebookSdk $fb) {
       // . . .
    }
}

// Or even a closure
Route::get('/facebook/login', function(SammyK\LaravelFacebookSdk\LaravelFacebookSdk $fb) {
    // . . .
});

Configuration File

Note: As of version 3.4.0, publishing the config file is optional as long as you set your required config values.

Also note: The config file contains a default Graph API version that gets bumped up to the latest stable version periodically which might cause a breaking change when you update this package in a minor or patch version. It is recommended that you still publish the config file and update the Graph API version on your own time to prevent breaking things.

After creating an app in Facebook, you'll need to provide the app ID and secret. In Laravel you can publish the configuration file with artisan.

$ php artisan vendor:publish --provider="SammyK\LaravelFacebookSdk\LaravelFacebookSdkServiceProvider" --tag="config"

Where's the file? Laravel 5 will publish the config file to /config/laravel-facebook-sdk.php.

In Lumen you'll need to manually copy the config file from /src/config/laravel-facebook-sdk.php to your config folder in your base project directory. Lumen doesn't have a /config folder by default so you'll need to create it if you haven't already.

Required config values

You'll need to update the app_id and app_secret values in the config file with your app ID and secret.

By default the configuration file will look to environment variables for your app ID and secret. It is recommended that you use environment variables to store this info in order to protect your app secret from attackers. Make sure to update your /.env file with your app ID & secret.

FACEBOOK_APP_ID=1234567890
FACEBOOK_APP_SECRET=SomeFooAppSecret

User Login From Redirect Example

Here's a full example of how you might log a user into your app using the redirect method.

This example also demonstrates how to exchange a short-lived access token with a long-lived access token and save the user to your users table if the entry doesn't exist.

Finally it will log the user in using Laravel's built-in user authentication.

Sessions in Lumen: The "login from redirect" functionality relies on sessions to store a CSRF token. Since sessions don't exist in Lumen 5.2+, you'll need to obtain an access token using a different method. For testing you can just grab an access token from the Graph API Explorer (make sure to select your app from the "Application" drop down).

// Generate a login URL
Route::get('/facebook/login', function(SammyK\LaravelFacebookSdk\LaravelFacebookSdk $fb)
{
    // Send an array of permissions to request
    $login_url = $fb->getLoginUrl(['email']);

    // Obviously you'd do this in blade :)
    echo '<a href="' . $login_url . '">Login with Facebook</a>';
});

// Endpoint that is redirected to after an authentication attempt
Route::get('/facebook/callback', function(SammyK\LaravelFacebookSdk\LaravelFacebookSdk $fb)
{
    // Obtain an access token.
    try {
        $token = $fb->getAccessTokenFromRedirect();
    } catch (Facebook\Exceptions\FacebookSDKException $e) {
        dd($e->getMessage());
    }

    // Access token will be null if the user denied the request
    // or if someone just hit this URL outside of the OAuth flow.
    if (! $token) {
        // Get the redirect helper
        $helper = $fb->getRedirectLoginHelper();

        if (! $helper->getError()) {
            abort(403, 'Unauthorized action.');
        }

        // User denied the request
        dd(
            $helper->getError(),
            $helper->getErrorCode(),
            $helper->getErrorReason(),
            $helper->getErrorDescription()
        );
    }

    if (! $token->isLongLived()) {
        // OAuth 2.0 client handler
        $oauth_client = $fb->getOAuth2Client();

        // Extend the access token.
        try {
            $token = $oauth_client->getLongLivedAccessToken($token);
        } catch (Facebook\Exceptions\FacebookSDKException $e) {
            dd($e->getMessage());
        }
    }

    $fb->setDefaultAccessToken($token);

    // Save for later
    Session::put('fb_user_access_token', (string) $token);

    // Get basic info on the user from Facebook.
    try {
        $response = $fb->get('/me?fields=id,name,email');
    } catch (Facebook\Exceptions\FacebookSDKException $e) {
        dd($e->getMessage());
    }

    // Convert the response to a `Facebook/GraphNodes/GraphUser` collection
    $facebook_user = $response->getGraphUser();

    // Create the user if it does not exist or update the existing entry.
    // This will only work if you've added the SyncableGraphNodeTrait to your User model.
    $user = App\User::createOrUpdateGraphNode($facebook_user);

    // Log the user into Laravel
    Auth::login($user);

    return redirect('/')->with('message', 'Successfully logged in with Facebook');
});

For more details on the ways to authenticate a user, see Facebook Login.

Making Requests To Facebook

Requests to Facebook are made via the Graph API. This package is a Laravel wrapper for the official Facebook PHP SDK v5 so all the methods available to the official SDK are also available in this package.

Get User Info

The following snippet will retrieve a User node representing the logged in user.

try {
  $response = $fb->get('/me?fields=id,name,email', 'user-access-token');
} catch(\Facebook\Exceptions\FacebookSDKException $e) {
  dd($e->getMessage());
}

$userNode = $response->getGraphUser();
printf('Hello, %s!', $userNode->getName());

See more about the get() method.

Facebook Login

When we say "log in with Facebook", we really mean "obtain a user access token to make calls to the Graph API on behalf of the user." This is done through Facebook via OAuth 2.0. There are a number of ways to log a user in with Facebook using what the Facbeook PHP SDK calls "helpers".

The four supported login methods are:

  1. Login From Redirect (OAuth 2.0)
  2. Login From JavaScript (with JS SDK cookie)
  3. Login From App Canvas (with signed request)
  4. Login From Page Tab (with signed request)

Login From Redirect

One of the most common ways to log a user into your app is by using a redirect URL.

The idea is that you generate a unique URL that the user clicks on. Once the user clicks the link they will be redirected to Facebook asking them to grant any permissions your app is requesting. Once the user responds, Facebook will redirect the user back to a callback URL that you specify with either a successful response or an error response.

The redirect helper can be obtained using the SDK's getRedirectLoginHelper() method.

Generating a login URL

You can get a login URL just like you you do with the Facebook PHP SDK v5.

Route::get('/facebook/login', function(SammyK\LaravelFacebookSdk\LaravelFacebookSdk $fb) {
    $login_link = $fb
            ->getRedirectLoginHelper()
            ->getLoginUrl('https://exmaple.com/facebook/callback', ['email', 'user_events']);
    
    echo '<a href="' . $login_link . '">Log in with Facebook</a>';
});

But if you set the default_redirect_uri callback URL in the config file, you can use the getLoginUrl() wrapper method which will default the callback URL (default_redirect_uri) and permission scope (default_scope) to whatever you set in the config file.

$login_link = $fb->getLoginUrl();

Alternatively you can pass the permissions and a custom callback URL to the wrapper to overwrite the default config.

Note: Since the list of permissions sometimes changes but the callback URL usually stays the same, the permissions array is the first argument in the getLoginUrl() wrapper method which is the reverse of the SDK's method getRedirectLoginHelper()->getLoginUrl($url, $permissions).

$login_link = $fb->getLoginUrl(['email', 'user_status'], 'https://exmaple.com/facebook/callback');
// Or, if you want to default to the callback URL set in the config
$login_link = $fb->getLoginUrl(['email', 'user_status']);

Obtaining an access token from a callback URL

After the user has clicked on the login link from above and confirmed or denied the app permission requests, they will be redirected to the specified callback URL.

The standard "SDK" way to obtain an access token on the callback URL is as follows:

Route::get('/facebook/callback', function(SammyK\LaravelFacebookSdk\LaravelFacebookSdk $fb) {
    try {
        $token = $fb
            ->getRedirectLoginHelper()
            ->getAccessToken();
    } catch (Facebook\Exceptions\FacebookSDKException $e) {
        // Failed to obtain access token
        dd($e->getMessage());
    }
});

There is a wrapper method for getRedirectLoginHelper()->getAccessToken() in LaravelFacebookSdk called getAccessTokenFromRedirect() that defaults the callback URL to the laravel-facebook-sdk.default_redirect_uri config value.

Route::get('/facebook/callback', function(SammyK\LaravelFacebookSdk\LaravelFacebookSdk $fb) {
    try {
        $token = $fb->getAccessTokenFromRedirect();
    } catch (Facebook\Exceptions\FacebookSDKException $e) {
        // Failed to obtain access token
        dd($e->getMessage());
    }
    
    // $token will be null if the user denied the request
    if (! $token) {
        // User denied the request
    }
});

Login From JavaScript

If you're using the JavaScript SDK, you can obtain an access token from the cookie set by the JavaScript SDK.

By default the JavaScript SDK will not set a cookie, so you have to explicitly enable it with cookie: true when you init() the SDK.

FB.init({
  appId      : 'your-app-id',
  cookie     : true,
  version    : 'v2.10'
});

After you have logged a user in with the JavaScript SDK using FB.login(), you can obtain a user access token from the signed request that is stored in the cookie that was set by the JavaScript SDK.

Route::get('/facebook/javascript', function(SammyK\LaravelFacebookSdk\LaravelFacebookSdk $fb) {
    try {
        $token = $fb->getJavaScriptHelper()->getAccessToken();
    } catch (Facebook\Exceptions\FacebookSDKException $e) {
        // Failed to obtain access token
        dd($e->getMessage());
    }

    // $token will be null if no cookie was set or no OAuth data
    // was found in the cookie's signed request data
    if (! $token) {
        // User hasn't logged in using the JS SDK yet
    }
});

Login From App Canvas

TokenMismatchException: Default Laravel installations will throw a TokenMismatchException when you try to view your app in Facebook. See how to fix this issue.

If your app lives within the context of a Facebook app canvas, you can obtain an access token from the signed request that is POST'ed to your app on the first page load.

Note: The canvas helper only obtains an existing access token from the signed request data received from Facebook. If the user visiting your app has not authorized your app yet or their access token has expired, the getAccessToken() method will return null. In that case you'll need to log the user in with either a redirect or JavaScript.

Use the SDK's canvas helper to obtain the access token from the signed request data.

Route::match(['get', 'post'], '/facebook/canvas', function(SammyK\LaravelFacebookSdk\LaravelFacebookSdk $fb) {
    try {
        $token = $fb->getCanvasHelper()->getAccessToken();
    } catch (Facebook\Exceptions\FacebookSDKException $e) {
        // Failed to obtain access token
        dd($e->getMessage());
    }

    // $token will be null if the user hasn't authenticated your app yet
    if (! $token) {
        // . . .
    }
});

Login From Page Tab

TokenMismatchException: Default Laravel installations will throw a TokenMismatchException when you try to view your page tab in Facebook. See how to fix this issue.

If your app lives within the context of a Facebook Page tab, that is the same as an app canvas and the "Login From App Canvas" method will also work to obtain an access token. But a Page tab also has additional data in the signed request.

The SDK provides a Page tab helper to obtain an access token from the signed request data within the context of a Page tab.

Route::match(['get', 'post'], '/facebook/page-tab', function(SammyK\LaravelFacebookSdk\LaravelFacebookSdk $fb) {
    try {
        $token = $fb->getPageTabHelper()->getAccessToken();
    } catch (Facebook\Exceptions\FacebookSDKException $e) {
        // Failed to obtain access token
        dd($e->getMessage());
    }

    // $token will be null if the user hasn't authenticated your app yet
    if (! $token) {
        // . . .
    }
});

Other authorization requests

Facebook supports two other types of authorization URL's - rerequests and re-authentications.

Rerequests

Rerequests (or re-requests?) ask the user again for permissions they have previously declined. It's important to use a rerequest URL for this instead of just redirecting them with the normal log in link because:

Once someone has declined a permission, the Login Dialog will not re-ask them for it unless you explicitly tell the dialog you're re-asking for a declined permission. - Facebook Documentation

You can generate a rerequest URL using the getReRequestUrl() method.

$rerequest_link = $fb->getReRequestUrl(['email'], 'https://exmaple.com/facebook/login');
// Or, if you want to default to the callback URL set in the config
$rerequest_link = $fb->getReRequestUrl(['email']);

Re-authentications

Re-authentications force a user to confirm their identity by asking them to enter their Facebook account password again. This is useful for adding another layer of security before changing or view sensitive data on your web app.

You can generate a re-authentication URL using the getReAuthenticationUrl() method.

$re_authentication_link = $fb->getReAuthenticationUrl(['email'], 'https://exmaple.com/facebook/login');
// Or, if you want to default to the callback URL set in the config
$re_authentication_link = $fb->getReAuthenticationUrl(['email']);
// Or without permissions
$re_authentication_link = $fb->getReAuthenticationUrl();

Saving the Access Token

In most cases you won't need to save the access token to a database unless you plan on making requests to the Graph API on behalf of the user when they are not browsing your app (like a 3AM CRON job for example).

After you obtain an access token, you can store it in a session to be used for subsequent requests.

Session::put('facebook_access_token', (string) $token);

Then in each script that makes calls to the Graph API you can pull the token out of the session and set it as the default.

$token = Session::get('facebook_access_token');
$fb->setDefaultAccessToken($token);

Saving data from Facebook in the database

Saving data received from the Graph API to a database can sometimes be a tedious endeavor. Since the Graph API returns data in a predictable format, the SyncableGraphNodeTrait can make saving the data to a database a painless process.

Any Eloquent model that implements the SyncableGraphNodeTrait will have the createOrUpdateGraphNode() method applied to it. This method really makes it easy to take data that was returned directly from Facebook and create or update it in the local database.

use SammyK\LaravelFacebookSdk\SyncableGraphNodeTrait;

class Event extends Eloquent {
    use SyncableGraphNodeTrait;
}

For example if you have an Eloquent model named Event, here's how you might grab a specific event from the Graph API and insert it into the database as a new entry or update an existing entry with the new info.

$response = $fb->get('/some-event-id?fields=id,name');
$eventNode = $response->getGraphEvent();

// A method called createOrUpdateGraphNode() on the `Event` eloquent model
// will create the event if it does not exist or it will update the existing
// record based on the ID from Facebook.
$event = Event::createOrUpdateGraphNode($eventNode);

The createOrUpdateGraphNode() will automatically map the returned field names to the column names in your database. If, for example, your column names on the events table don't match the field names for an Event node, you can map the fields.

Field Mapping

Since the names of the columns in your database might not match the names of the fields of the Graph nodes, you can map the field names in your User model using the $graph_node_field_aliases static variable.

The keys of the array are the names of the fields on the Graph node. The values of the array are the names of the columns in the local database.

use SammyK\LaravelFacebookSdk\SyncableGraphNodeTrait;

class User extends Eloquent implements UserInterface
{
    use SyncableGraphNodeTrait;
    
    protected static $graph_node_field_aliases = [
        'id' => 'facebook_user_id',
        'name' => 'full_name',
        'graph_node_field_name' => 'database_column_name',
    ];
}

Specifying "fillable" fields

By default the createOrUpdateGraphNode() method will try to insert all the fields of a node into the database. But sometimes the Graph API will return fields that you didn't specifically ask for and don't exist in your database. In those cases we can white list specific fields with the $graph_node_fillable_fields property.

use SammyK\LaravelFacebookSdk\SyncableGraphNodeTrait;

class Event extends Eloquent
{
    use SyncableGraphNodeTrait;
    
    protected static $graph_node_fillable_fields = ['id', 'name', 'start_time'];
}

Use the name of the database column. For example, if you've aliased the id field to the facebook_id column in your databse, you'll want to specify facebook_id in your $graph_node_fillable_fields array.

Nested field mapping

Since the Graph API will return some of the fields from a request as other nodes/objects, you can reference the fields on those using Laravel's array_dot() notation.

An example might be making a request to the /me/events endpoint and looping through all the events and saving them to your Event model. The Event node will return the place.location fields as Location nodes. The response data might look like this:

{
  "data": [
    {
      "id": "123", 
      "name": "Foo Event", 
      "place": {
        "location": {
          "city": "Dearborn", 
          "state": "MI", 
          "country": "United States", 
          . . .
        }, 
        "id": "827346"
      }
    },
    . . .
  ]
}

Let's assume you have an event table like this:

Schema::create('events', function(Blueprint $table)
{
    $table->increments('id');
    $table->bigInteger('facebook_id')->nullable()->unsigned()->index();
    $table->string('name')->nullable();
    $table->string('city')->nullable();
    $table->string('state')->nullable();
    $table->string('country')->nullable();
});

Here's how you would map the nested fields to your database table in your Event model:

use SammyK\LaravelFacebookSdk\SyncableGraphNodeTrait;

class Event extends Eloquent
{
    use SyncableGraphNodeTrait;
    
    protected static $graph_node_field_aliases = [
        'id' => 'facebook_id',
        'place.location.city' => 'city',
        'place.location.state' => 'state',
        'place.location.country' => 'country',
    ];
}

Date formats

The Facebook PHP SDK will convert most date formats into instances of DateTime. This can be problematic when you want to insert a date/time value into the database (e.g. the start_time field of an Event node).

By default the SyncableGraphNodeTrait will convert all DateTime instances to the following date() format:

Y-m-d H:i:s

That should the proper format for most cases on most relational databases. But this format is missing the timezone which might be important to your application. Furthermore if you're storing the date/time values in a different format, you'll want to customize the format that DateTime instances get converted to. To do this just add a $graph_node_date_time_to_string_format property to your model and set it to any valid date format.

use SammyK\LaravelFacebookSdk\SyncableGraphNodeTrait;

class Event extends Eloquent
{
    use SyncableGraphNodeTrait;
    
    protected static $graph_node_date_time_to_string_format = 'c'; # ISO 8601 date
}

Logging The User Into Laravel

The Laravel Facebook SDK makes it easy to log a user in with Laravel's built-in authentication driver.

Updating The Users Table

In order to get Facebook authentication working with Laravel's built-in authentication, you'll need to store the Facebook user's ID in your user's table.

Naturally you'll need to create a column for every other piece of information you want to keep about the user.

You can store the access token in the database if you need to make requests on behalf of the user when they are not browsing your app (like a 3AM cron job). But in general you won't need to store the access token in the database.

You'll need to generate a migration to modify your users table and add any new columns.

Note: Make sure to change <name-of-users-table> to the name of your user table.

$ php artisan make:migration add_facebook_columns_to_users_table --table="<name-of-users-table>"

Now update the migration file to include the new fields you want to save on the user. At minimum you'll need to save the Facebook user ID.

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class AddFacebookColumnsToUsersTable extends Migration
{
    public function up()
    {
        Schema::table('users', function(Blueprint $table)
        {
            // If the primary id in your you user table is different than the Facebook id
            // Make sure it's an unsigned() bigInteger()
            $table->bigInteger('facebook_user_id')->unsigned()->index();
            // Normally you won't need to store the access token in the database
            $table->string('access_token')->nullable();
        });
    }

    public function down()
    {
        Schema::table('users', function(Blueprint $table)
        {
            $table->dropColumn(
                'facebook_user_id',
                'access_token'
            );
        });
    }
}

Don't forget to run the migration.

$ php artisan migrate

If you plan on using the Facebook user ID as the primary key, make sure you have a column called id that is an unsigned big integer and indexed. If you are storing the Facebook ID in a different field, make sure that field exists in the database and make sure to map to it in your model to your custom id name.

If you're using the Eloquent ORM and storing the access token in the database, make sure to hide the access_token field from possible exposure in your User model.

Don't forget to add the SyncableGraphNodeTrait to your user model so you can sync your model with data returned from the Graph API.

# User.php
use SammyK\LaravelFacebookSdk\SyncableGraphNodeTrait;

class User extends Eloquent implements UserInterface {
    use SyncableGraphNodeTrait;

    protected $hidden = ['access_token'];
}

Logging the user into Laravel

After the user has logged in with Facebook and you've obtained the user ID from the Graph API, you can log the user into Laravel by passing the logged in user's User model to the Auth::login() method.

class FacebookController {
    public function getUserInfo(SammyK\LaravelFacebookSdk\LaravelFacebookSdk $fb) {
       try {
           $response = $fb->get('/me?fields=id,name,email');
       } catch (Facebook\Exceptions\FacebookSDKException $e) {
           dd($e->getMessage());
       }
       
       // Convert the response to a `Facebook/GraphNodes/GraphUser` collection
       $facebook_user = $response->getGraphUser();
       
       // Create the user if it does not exist or update the existing entry.
       // This will only work if you've added the SyncableGraphNodeTrait to your User model.
       $user = App\User::createOrUpdateGraphNode($facebook_user);
       
       // Log the user into Laravel
       Auth::login($user);
    }
}

Working With Multiple Apps

If you have multiple Facebook apps that you'd like to use in the same script or you want to tweak the settings during runtime, you can create a new instance of LaravelFacebookSdk with the custom settings.

Route::get('/example', function(SammyK\LaravelFacebookSdk\LaravelFacebookSdk $fb) {
    // All the possible configuration options are available here
    $fb2 = $fb->newInstance([
      'app_id' => env('FACEBOOK_APP_ID2'),
      'app_secret' => env('FACEBOOK_APP_SECRET2'),
      'default_graph_version' => 'v2.10',
      // . . .
    ]);
});

Error Handling

The Facebook PHP SDK throws Facebook\Exceptions\FacebookSDKException exceptions. Whenever there is an error response from Graph, the SDK will throw a Facebook\Exceptions\FacebookResponseException which extends from Facebook\Exceptions\FacebookSDKException. If a Facebook\Exceptions\FacebookResponseException is thrown you can grab a specific exception related to the error from the getPrevious() method.

try {
    // Stuffs here
} catch (Facebook\Exceptions\FacebookResponseException $e) {
    $graphError = $e->getPrevious();
    echo 'Graph API Error: ' . $e->getMessage();
    echo ', Graph error code: ' . $graphError->getCode();
    exit;
} catch (Facebook\Exceptions\FacebookSDKException $e) {
    echo 'SDK Error: ' . $e->getMessage();
    exit;
}

The LaravelFacebookSdk does not throw any custom exceptions.

Troubleshooting

Getting a TokenMismatchException with canvas apps

If your app is being served from within the context of an app canvas or Page tab, you'll likely see a TokenMismatchException error when you try to view the app on Facebook. This is because Facebook will render your app by sending a POST request to it with a signed_request param and since Laravel 5 has CSRF protection that is enabled for every non-read request, the error is triggered.

Although it's possible to disable this feature completely, it's certainly not recommended as CSRF protection is an important security feature to have on your site and it should be enabled on every route by default.

Disable CSRF on endpoints in Laravel 5.1 & 5.2

Add an exception to your canvas endpoint to the $except array in your app\Http\Middleware\VerifyCsrfToken.php file.

<?php

namespace App\Http\Middleware;

use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as BaseVerifier;

class VerifyCsrfToken extends BaseVerifier
{
    /**
     * The URIs that should be excluded from CSRF verification.
     *
     * @var array
     */
    protected $except = [
        'facebook/canvas',
        'facebook/page-tab',
        // ... insert all your canvas endpoints here
    ];
}

Disable CSRF on endpoints in Laravel 5.0

In Laravel 5.0 it was a bit trickier to disable CSRF verification but there is an article that explains how to disable CSRF protection for specific routes in Laravel 5.0.

In your app\Http\Middleware\VerifyCsrfToken.php file, add an excludedRoutes() method. Then create an array of routes that are endpoints to you canvas app or page tab. The complete file looks like this:

<?php namespace App\Http\Middleware;

use Closure;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as BaseVerifier;
use Illuminate\Session\TokenMismatchException;

class VerifyCsrfToken extends BaseVerifier
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     *
     * @throws TokenMismatchException
     */
    public function handle($request, Closure $next)
    {
        if ($this->isReading($request) || $this->excludedRoutes($request) || $this->tokensMatch($request)) {
            return $this->addCookieToResponse($request, $next($request));
        }

        throw new TokenMismatchException;
    }

    /**
     * Ignore CSRF on these routes.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return bool
     */
    private function excludedRoutes($request)
    {
        $routes = [
          'my-app/canvas',
          'my-app/page-tab',
          // ... insert all your canvas endpoints here
        ];

        foreach($routes as $route){
            if ($request->is($route)) {
                return true;
            }
        }

        return false;
    }
}

Getting a QueryException when saving a User

If you're using MySQL, you might get a QueryException when saving a user to the database with createOrUpdateGraphNode().

QueryException in Connection.php line 754:
SQLSTATE[HY000]: General error: 1364 Field 'password' doesn't have a default value

This is because by default, strict mode is enabled which sets sql_mode to include STRICT_TRANS_TABLES. Since we don't need a password for users logging in with Facebook, this field will be empty. A workaround to this error is to set strict to false for the MySQL diver in your config/database.php file.

Testing

The tests are written with phpunit. You can run the tests from the root of the project directory with the following command.

$ ./vendor/bin/phpunit

Contributing

Please see CONTRIBUTING for details.

Credits

This package is maintained by Sammy Kaye Powers. See a full list of contributors.

License

The MIT License (MIT). Please see License File for more information.

Comments
  • Cross-site request forgery validation failed. Required param

    Cross-site request forgery validation failed. Required param "state" missing.

    I dont know why,but I started getting this issue suddenly.I tried to debug and found in the FacebookRedirectLoginHelper the function validateCsrf() does not get the savedstate $savedState = $this->persistentDataHandler->get('state'); I am not how to resolve this.I tried printing both the $state and $savedState and I get $savedState as null Where am I making a mistake with this?

    class FacebookController extends Controller {
    public function fbConnect(LaravelFacebookSdk $fb)
    {
        // Obtain an access token.
        try {
            $token = $fb
                ->getRedirectLoginHelper()
                ->getAccessToken();
        } catch (Facebook\Exceptions\FacebookSDKException $e) {
            dd($e->getMessage());
        }
        dd($token);
        // Access token will be null if the user denied the request
        // or if someone just hit this URL outside of the OAuth flow.
        if (! $token) {
            // Get the redirect helper
            $helper = $fb->getRedirectLoginHelper();
    
            if (! $helper->getError()) {
                abort(403, 'Unauthorized action.');
            }
    
            // User denied the request
            dd(
                $helper->getError(),
                $helper->getErrorCode(),
                $helper->getErrorReason(),
                $helper->getErrorDescription()
            );
        }
      //Long lived token code after this
    
    opened by sachintaware 29
  • SammyK \ FacebookQueryBuilder \ FacebookQueryBuilderException (10)  Graph returned an error response.

    SammyK \ FacebookQueryBuilder \ FacebookQueryBuilderException (10) Graph returned an error response.

    When using the following code Laravel 4 fired an exception : Facebook::setAppCredentials('########', '#############');

        // This access token will be used for all calls to Graph.
        Facebook::setAccessToken('ff5ab5e96377be16436c9f2fe751b4c3');
    
        // Get the logged in user's profile.
        $user = Facebook::object('me')->fields('id', 'email')->get();
    

    Exeception - SammyK \ FacebookQueryBuilder \ FacebookQueryBuilderException (10) Graph returned an error response.

    opened by kuldeep1984 29
  • About Facebook::getTokenFromRedirect()

    About Facebook::getTokenFromRedirect()

    i read about this instruction

    there is a wrapper for getTokenFromRedirect() that defaults the callback URL to whatever is set in the config.

    But when i set redirect_uri in config, the function Facebook::getLoginUrl() run normally with redirect_uri from config file

    And when i using getTokenFromRedirect() without parameter, i getting error

    Unable to obtain access token from redirect facebook

    But if i set the paramter like this Facebook::getTokenFromRedirect(url('/whatever/link/'));

    it's return token with experies date.

    opened by pedox 27
  • Flow

    Flow

    Hi @SammyK, Thank you for your amazing work! If you don't mind I would ask you a couple of questions.

    I read your articles on https://www.sammyk.me I read your documentation. I'm practicing on a personal project hosted on my localhost running with Laravel 4.2. My Facebook app is well configured.

    So I have a page "/login" which displays 3 social login buttons "1)Facebook" ; "2)Google" ; "3)Twitter"

    When I click on "1)Facebook" it redirects to "/auth/facebook" and starts the login flow.

    What is the purpose of the following line?

    Facebook::setAccessToken($token);
    

    Once this line is executed, I can perform FbGraph requests. What happens if user go to another page? For example "/profile" On this route, I need to perform a request on the FbGraph again.

    For now, if I try it says:

    Method Facebook\Entities\AccessToken::__toString() must return a string value"
    

    What is the flow I'm missing from the first steps? I guess I need to store the token to the session then retrieve it from the route /profile to be able to perform requests? I tought it was the work done by setAccessToken method! Is it?

    Can you please give me some directions about the flow to follow? The goal of the token is to not be asked at each request. What is the best way to store it and use it.

    With best regards,

    J.

    opened by jrean 18
  • Facebook throws configuration error

    Facebook throws configuration error "Given URL is not allowed by the Application configuration

    Hello there, first thanks for the package. I am trying to log a user in with facebook using your package but facebook keeps throwing this error.

    Given URL is not allowed by the Application configuration.: One or more of the given URLs is not allowed by the App's settings. It must match the Website URL or Canvas URL, or the domain must be a subdomain of one of the App's domains.

    I know what this means, and i have checked and triple checked that everything is right in my app config at facebook. All the domains and such. I think there must be something with the php sdk v4 thats preventing user login because when i tried login with the JS SDK with the same app config at facebook it worked perfect. I have done research and i can't figure this out. Any help would be greatly appreciated. Thanks.

    opened by mateoprifti 17
  • App ID not supplied in config

    App ID not supplied in config

    I've published the config file with app id and app secret, but I get the following error

    FacebookSDKException in Facebook.php line 133: Required "app_id" key not supplied in config and could not find fallback environment variable "1621623694787935"

    opened by rajgaurav1 16
  • Not able to use Facebook facade

    Not able to use Facebook facade

    Not sure if its just me or for everyone... I am not able to use "Facebook" facade. I added alias and provider entry in my app.php, created proper configs as per readme file. Please help if there is a known issue or something missing in readme or its just me :(

    opened by vipulmehta13 12
  • Token still sometimes null from getTokenFromRedirect()

    Token still sometimes null from getTokenFromRedirect()

    Sorry. Please don't get a court order or something against me asking so many questions :)

    I've basically exactly copied your example code for logging in a user by Facebook. Here it is:

        public function facebooklogin()
        {
            try
            {
                $token = Facebook::getTokenFromRedirect();
    
                if(!$token)
                {
                    ob_start();
                    var_dump(Input::all());
                    $params = ob_get_contents();
                    ob_end_clean();
                    Log::error($params);
                    return Redirect::to('/error')->with('error', '<!snip!> (Error 101)');
                }
                ...
    

    At this point it hits that redirect and we're done. The error code was just so I knew at which point the error redirect happens. The log shows the redirect URL parameters look like this:

    [2015-01-17 14:20:46] production.ERROR: array(2) {
      ["code"]=>
      string(323) "AQCHTNya-xzAc9eOgs7gD1RdgsG90Tgx_WqZvpTtoag99El8d27A7FsSKyUm6QfvU8eZcuQh6PPsselYemqqQ2dXHbPlP2gJknA949-75M5b1EXVaBJ7DgWymG6JHh6r9T7-STbVceTJqQNCSVTZ0NVBsn_aYTG852aMMFZS0fPgGli98X3hgzNdod4nZpJ4lBM2XOYtUPeyIsI780zP1lMy3wcxtmEeeHQVeC4LRWUkahqoOBfiQAawRDO27slChM3NdyIUvoj4JpINCv-RW-mw5IUe3RqruohlcXi9DoL34avGxoGwc7pUcFoW-SB6v14"
      ["state"]=>
      string(32) "611e655b35c625ea319b0c482a3810d5"
    }
    

    Which presumably means the token wasn't empty. Am I missing something? Other than a clue? Or is it a bug?

    Final point: this has never happened to me when testing. It's happened to some people while testing, and (in what is probably a coincidence) they were using the built in Android browser on their phones.

    Update: I logged the whole URL and there's nothing else to it; just code and state. Also, I assume this is correct, but this is the relevant part of the config:

    'default_scope' => ['email'],
    'default_redirect_uri' => '/facebook/login',
    
    opened by robertlagrant 12
  • All FQB methods? getTokenFromJavascript() doesn't work?

    All FQB methods? getTokenFromJavascript() doesn't work?

    Hi! This is probably me doing something wrong: but I try to authenticate a user from the FB.js SDK. Working with a redirect (without the fb.js SDK) works with:

    $token = Facebook::getTokenFromRedirect();
    

    However,

    $token = Facebook::getTokenFromJavascript()
    

    doesn't work. The function doesn't exists. What goes wrong here? The frontpage says "all Facebook Query Builder functions are supported". I'm using version 1.2 as I'm on laravel 4.2 Thanks!

    bug 
    opened by PanMan 11
  • Method Facebook\Entities\AccessToken::__toString() must return a string value

    Method Facebook\Entities\AccessToken::__toString() must return a string value

    Hello can you help me now I got a message error as "Method Facebook\Entities\AccessToken::__toString() must return a string value"!

    so how can I take it out?

    Thanks!

    opened by theavuthnh 11
  • Batch API calls

    Batch API calls

    First of all, thanks for your great package. I'm starting with a new project on Laravel and I want to know is there is a way to make batch API calls with this package.

    Thanks in advance!

    opened by juanramonperez 11
  • Laravel 8 Support ?

    Laravel 8 Support ?

    I'm upgrading an old project, I was able to use Laravel 7 fork from https://github.com/s1rc/LaravelFacebookSdk . Now I'm working on Laravel 8. Are there any other Laravel 8 supported Repos? or Alternative similar packages that I can use?

    opened by devinyasas 0
  • FB Login -> Error: Undefined offset: 1

    FB Login -> Error: Undefined offset: 1

    Hi,

    A new installation of the SDK, I'm getting Error: Undefined offset: 1 on facebook login during the callback.

    Script file referenced is vendor\facebook\graph-sdk\src\Facebook\Http\GraphRawResponse.php

    Line 108

    Below code in the graph sciprt file:

    public function setHttpResponseCodeFromHeader($rawResponseHeader)
        {
            preg_match('|HTTP/\d\.\d\s+(\d+)\s+.*|', $rawResponseHeader, $match);
            $this->httpResponseCode = (int)$match[1];
        }
    

    Does anyone have a suggestion for fixing this?

    The callback itself comes as https://mywebsite/facebook/callback?code=

    Thanks

    opened by amsmithmt 0
  • Access token was not returned from Graph

    Access token was not returned from Graph

    Hi, my app was working fine with LaravelFacebookSdk but from about a week ago I kept seeing this error:

    Facebook\Exceptions\FacebookSDKException thrown with message "Access token was not returned from Graph."

    Any idea what is happening?

    opened by eboye 3
  • When i'm trying to execute php /path/to/artisan schedule:run, it's give this error ?

    When i'm trying to execute php /path/to/artisan schedule:run, it's give this error ?

    PHP Notice: Undefined index: SERVER_NAME in /usr/home/html/production/libs/laravel/app_social/config/laravel-facebook-sdk.php on line 2 PHP Notice: Undefined index: SERVER_NAME in /usr/home/html/production/libs/laravel/app_social/config/laravel-facebook-sdk.php on line 5 PHP Notice: Undefined index: SERVER_NAME in /usr/home/html/production/libs/laravel/app_social/config/laravel-facebook-sdk.php on line 8 PHP Catchable fatal error: Argument 2 passed to IlluminateRoutingUrlGenerator::__construct() must be an instance of IlluminateHttpRequest, null given, called in /usr/home/html/production/libs/laravel/app_social/vendor/laravel/framework/src/Illuminate/Routing/RoutingServiceProvider.php on line 56 and defined in /usr/home/html/production/libs/laravel/app_social/vendor/laravel/framework/src/Illuminate/Routing/UrlGenerator.php on line 95

    opened by mehdirochdi 0
Owner
Sammy Kaye Powers
Telemetry all the things
Sammy Kaye Powers
The Facebook SDK for PHP provides a native interface to the Graph API and Facebook Login

Facebook SDK for PHP (v5) This repository contains the open source PHP SDK that allows you to access the Facebook Platform from your PHP app. Installa

Meta Archive 3.1k Dec 30, 2022
Facebook SDK for PHP (v6) - allows you to access the Facebook Platform from your PHP app

Facebook SDK for PHP (v6) This repository contains the open source PHP SDK that allows you to access the Facebook Platform from your PHP app. Installa

null 0 Aug 10, 2022
Fully documented & tested Laravel 9 RESTful books API scraped from Gramedia.

Laravel Books API Introduction This app provides a list of books in a RESTful API. Source of data obtained from Gramedia by using the web scraping tec

Yusuf T. 44 Dec 23, 2022
Facebook Query Builder: A query builder for nested requests in the Facebook Graph API

A query builder that makes it easy to create complex & efficient nested requests to Facebook's Graph API to get lots of specific data back with one request.

Sammy Kaye Powers 92 Dec 18, 2022
An SDK built to facilitate application development for Facebook Ads API.

Facebook Business SDK for PHP Introduction The Facebook Business SDK is a one-stop shop to help our partners better serve their businesses. Partners a

Meta 719 Dec 28, 2022
TP-Link modem API. Tested with m7200 LTE and m7000 LTE

TP-LINK M7000 - M7200 Modem API tpMIFI 4G LTE Modem API. ###Login and reboot device $tp = new \TPLink\TPLinkM7200("MODEM_PASSWORD"); $l = $tp->authent

null 8 Oct 26, 2022
Shopware PHP SDK is a simple SDK implementation of Shopware 6 APIs

Shopware PHP SDK is a simple SDK implementation of Shopware 6 APIs. It helps to access the API in an object-oriented way.

Thuong Le 77 Dec 19, 2022
Zoho CRM API SDK is a wrapper to Zoho CRM APIs. By using this sdk, user can build the application with ease

Archival Notice: This SDK is archived. You can continue to use it, but no new features or support requests will be accepted. For the new version, refe

null 81 Nov 4, 2022
Paynow SDK Laravel integration

About Laravel Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experie

Alfred Tanaka Kudiwahove 2 Sep 20, 2021
WordPress integration for globalis/chargebee-php-sdk

chargebee-php-sdk-wp Overview WordPress integration for globalis/chargebee-php-sdk Features Convert PSR-14 events into WordPress hooks Add query-monit

GLOBALIS media systems 7 Feb 17, 2022
Laravel wrapper for Facebook's GraphQL

Laravel GraphQL Use Facebook's GraphQL with Laravel 6.0+. It is based on the PHP port of GraphQL reference implementation. You can find more informati

Mikk Mihkel Nurges 1.9k Dec 31, 2022
A RESTful API package for the Laravel and Lumen frameworks.

The Dingo API package is meant to provide you, the developer, with a set of tools to help you easily and quickly build your own API. While the goal of

null 9.3k Jan 7, 2023
An easy to use Fractal wrapper built for Laravel and Lumen applications

An easy to use Fractal wrapper built for Laravel and Lumen applications The package provides a nice and easy wrapper around Fractal for use in your La

Spatie 1.8k Dec 30, 2022
Generates OpenApi specification for Laravel, Lumen or Dingo using a configuration array and cebe/php-openapi

OpenApi Generator for Laravel, Lumen and Dingo. About The openapi-gen package provides a convenient way to create OpenApi specifications for Laravel,

Jean Dormehl 5 Jan 25, 2022
API for Symbiota using the Lumen PHP PHP Micro-Framework By Laravel

symbiota-api API for Symbiota using the Lumen PHP PHP Micro-Framework By Laravel Laravel Lumen Official Documentation Documentation for the Lumen fram

Biodiversity Knowledge Integration Center 2 Jan 3, 2022
AWS Cognito package using the AWS SDK for PHP/Laravel

Laravel Package to manage Web and API authentication with AWS Cognito AWS Cognito package using the AWS SDK for PHP This package provides a simple way

EllaiSys 74 Nov 15, 2022
A Laravel 5+ (and 4) service provider for the AWS SDK for PHP

AWS Service Provider for Laravel 5/6/7/8 This is a simple Laravel service provider for making it easy to include the official AWS SDK for PHP in your

Amazon Web Services 1.5k Dec 28, 2022
Unofficial Firebase Admin SDK for PHP

Firebase Admin PHP SDK Table of Contents Overview Installation Documentation Support License Overview Firebase provides the tools and infrastructure y

kreait 1.9k Jan 3, 2023
Notion PHP SDK

Notion PHP SDK This is an unofficial PHP SDK for the new public Notion API. It's work in progress as we didn't get the change to be included to the pr

Codecycler 43 Nov 29, 2022