After a fresh Laravel installation run php artisan make:auth to generate the conventional form-based authentication scaffolding that will take care of your applications entire authentication system by setting up routes, views, and controllers for registration, authentication and password reset.
Now to setup Social authentication, we need to install laravel/socialite package by running composer require laravel/socialite. Laravel Socialite provides an eloquent way to authenticate with OAuth providers. It currently supports authentication with Facebook, Twitter, LinkedIn, Google, GitHub, and Bitbucket. But, there are adapters available for many other platforms developed by faustbrian. For this tutorial, I’m using Facebook OAuth for social authentication. We can start off by creating a new Facebook app by visiting developers.facebook.com. Name it whatever you want and enter your contact email address. Submit and fill in the captcha and your app will be created.
After creating your app, go to Settings > Basic. Click Show to reveal app secret.
Now we will use these OAuth credentials for Facebook in config/services.php
1 2 3 4 5 6 7 8 9 |
return [ [...] // other services 'facebook' => [ 'client_id' => env('FACEBOOK_CLIENT_ID'), // Your Facebook Client ID 'client_secret' => env('FACEBOOK_CLIENT_SECRET'), // Your Facebook Client Secret 'redirect' => env('FACEBOOK_REDIRECT'), ], ] |
Now edit your projects .env file and fill in your own app credentials at the end of the file.
1 2 3 4 5 |
[...] // other env variables FACEBOOK_CLIENT_ID=YOUR_APP_ID FACEBOOK_CLIENT_SECRET=YOUR_APP_SECRET FACEBOOK_REDIRECT=https://localhost:3000/login/facebook/callback |
You also need to update your apps Valid OAuth Redirect URIs to allow incoming authentication requests for your app. Go to your app products and add Facebook login. Go to its settings and add your OAuth redirect URL.
All apps created after March 2018 requires HTTPS for OAuth Redirects. What this means is that you must have HTTPS enabled for your site in order to use Facebook OAuth services. Enforce HTTPS option can’t be turned off for apps created after March 2018, you need to use HTTPS even if you’re in a test environment and requesting from your localhost. If you self-host your app on digitalocean or any other VPS server and owns a domain, you can easily setup free LetsEncrypt SSL certificate. If you don’t have HTTPS and redirect to OAuth, you’ll be welcomed with this message stating that
Insecure Login Blocked: You can’t get an access token or log in to this app from an insecure page. Try re-loading the page as https://
If you’ve managed to bypass this setting for your local dev environment, please share it by posting a comment. Now we’ll be adding a link to our existing login form that will take the user to facebook authentication page. Edit your existing login view resources/views/auth/login.blade.php and add following HTML code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
@extends('layouts.app') @section('content') <div class="container"> <div class="row"> <div class="col-md-8 col-md-offset-2"> <div class="panel panel-default"> <div class="panel-heading">Login</div> <div class="panel-body"...> <div class="panel-heading">Login with Facebook</div> <div class="panel-body"> <a class="btn btn-primary" href="/login/facebook"> Facebook Login </a> </div> </div> </div> </div> </div> @endsection |
We need to define routes and methods for Facebook authentication. We can start off by defining routes in routes/web.php file.
1 2 3 |
Route::get('/login/facebook', 'Auth\LoginController@redirectToFacebookProvider'); Route::get('login/facebook/callback', 'Auth\LoginController@handleProviderFacebookCallback'); |
and adding methods to handle requests in app/Http/Controllers/Auth/LoginController.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
/** * Redirect the user to the Facebook authentication page. * * @return \Illuminate\Http\Response */ public function redirectToFacebookProvider() { return Socialite::driver('facebook')->redirect(); } /** * Obtain the user information from Facebook. * * @return void */ public function handleProviderFacebookCallback() { $user = Socialite::driver('facebook')->user(); // Fetch authenticated user dd($user); } |
Now when users click on Facebook Login button, they will be redirected to the Facebook authentication page and after allowing the app to use your information, they will be redirected back to https://localhost:3000/login/facebook/callback URI which will call handleProviderFacebookCallback() method. We are fetching authenticated user by calling Socialite::driver('facebook')->user(); and dumping it.
To save the user, we need to setup database for our application. Add your database credentials in your project .env file.
1 2 3 |
DB_DATABASE=socialite DB_USERNAME=root DB_PASSWORD=secret |
We also need to run database migrations to create user table but before doing that we need to modify it to store OAuth user. Edit your CreateUsersTable Migrations which resides in database/migrations folder.
1 2 3 4 5 6 7 8 9 10 11 12 |
public function up() { Schema::create('users', function (Blueprint $table) { $table->increments('id'); $table->string('name'); $table->string('email')->unique(); $table->string('password')->nullable(); // Set to nullable $table->string('token'); // OAuth Token $table->rememberToken(); $table->timestamps(); }); } |
We made two changes to default migration. We are allowing nullable on password and adding a token column to user’s table to store OAuth token. Run php artisan migrate to migrate tables. Now we are modifying handleProviderFacebookCallback() method to create a new user when they redirect back after successful authentication from OAuth page.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
public function handleProviderFacebookCallback() { $auth_user = Socialite::driver('facebook')->user(); $user = User::updateOrCreate( [ 'email' => $auth_user->email ], [ 'token' => $auth_user->token, 'name' => $auth_user->name ] ); Auth::login($user, true); return redirect()->to('/'); // Redirect to a secure page } |
We are using Eqlouent’s updateOrCreate() method to create a new user. The first argument passed to this method check whether a user with this emails exists or not if it exists we update token and name columns of the user table. If it doesn’t exist we create a new user with email, token and name. Make sure you add token attribute to $fillable array on your User model to avoid mass Eloquent assignment exception.
1 2 3 |
protected $fillable = [ 'name', 'email', 'password', 'token' ]; |
After creating or updating user, we are using login method on Auth facade to sign them into our application and redirecting them to a secure page. From a security point of view, it’s not recommended to store OAuth tokens in your database. If you’re using OAuth to just authenticate users for your application and not storing token to make calls to service on the behalf of the user, then it is recommended that you do not store it in your database. If you put them in sessions, it will still be saved on disk and can be abused in case your machine gets compromised. The recommended way is to always encrypt them before storing them in database or sessions. You can use Laravel Encrypter which provides AES-256 and AES-128 encryption. You can decrypt token at any time and make call to the service. If you’ve followed all the steps and still having trouble setting up OAuth authentication, comment and I’ll try to help you with your issue.
I got an exception from null email.
How i can fix it?
Thank you so much.
Could you be more specific about your error? What were you doing when this error showed up?
Thanks for this great tutorial.,
Can you also provide resources/links if I was to use Laravel Socialite and authenticate an JS based web-apps (React or Angular)?
I have already setup the Passport configuration and the basic registration and login is already in place. Now I am on a point to extend the app to login via FB and Google.
Thanks!
make the email nullable in the User model and run migration on it.
Se alguém como eu, estiver utilizando o guard tymon/jwt-auth, e um model diferente do User; aconselho a seguinte configuração.
use Tymon\JWTAuth\Contracts\JWTSubject;
$tokenJWT = Auth::guard(‘other’)->fromUser($user);
return response()->json($tokenJWT);
Do you have any github repo?
Did you find a way to get around the https thing when developing locally?
configure your xampp to use https, Ive done it, look it up on google its not complicated
Use this post, to configurate your apache server to use SSL/HTTPS protocol for facebook oAuth
https://stackoverflow.com/questions/29047078/how-to-enable-https-localhost-url-in-wamp-server-v2-5
Also, you can use https://perials.com/enable-virtual-hosts-self-signed-ssl-wamp/ to configurate your virual host on port :443 (https)
Good luck! My friends <3
Token field is not nullable. Won’t it throw an error when a user uses the regular registration method to register?
Thank you so much, great tutorial.
Client error:
POST https://graph.facebook.com/v3.0/oauth/access_token
resulted in a400 Bad Request
response: {“error”:{“message”:”This authorization code has been used.”,”type”:”OAuthException”,”code”:100,”fbtrace_id”:”EQmH\/9ACL (truncated…)“Argument 1 passed to Illuminate\Auth\SessionGuard::login() must implement interface Illuminate\Contracts\Auth\Authenticatable, null given, called in C:\xampp\htdocs\fastcash\vendor\laravel\framework\src\Illuminate\Auth\AuthManager.php on line 292
if i logout from my app the informations for the user still saved in the database ??