Login with Twitter is a standard Authentication functionality for web and mobile applications. Twitter provides OAuth 1.0a and OAuth 2.0, two different Authentication APIs, for login through their application.
Before writing this tutorial, I tried authentication using OAuth1.0a and OAuth 2.0, but there is one major problem with OAuth 2.0. If you use OAuth 2.0 for authentication, the Twitter Developer Application does not provide an email ID for any user. You need to manually get the email from the User each time they log in through Twitter. If you don’t get the email, Laravel will throw the error saying, “User email should not be null.”
So, if you log in through Laravel, you need the User’s email address, and currently, Twitter API does not offer any options.
Based on that, I will use the OAuth1.0a API, which provides an option to get an email address for the User who tries to log in through the Laravel 11 application.
Here is the step-by-step guide to creating an authentication to Laravel 11 application with Twitter / X using the Socialite package:
Step 1: Installing Laravel 11 boilerplate
Install the Laravel using below command:
composer create-project --prefer-dist laravel/laravel twitterlogin
Go inside the project folder:
cd twitterlogin
Step 2: Configure the database
For this tutorial, I am using MySQL Database.
To connect our Laravel application to MySQL Database, you need to modify the .env file.
DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=8889 DB_DATABASE=twitterlogin DB_USERNAME=root DB_PASSWORD=root
Step 3: Install Jetstream
Jetstream implements your application’s login, registration, email verification, two-factor authentication, session management, API via Laravel Sanctum, and optional team management features.
To install Jetstream in Laravel, use the below command:
composer require laravel/jetstream
After installing, you need to publish Jetstream’s assets.
php artisan jetstream:install livewire
It will install some libraries and create tables and some configurations.
Step 4: Install the socialite package
The Socialite package is the go-to package for Social Authentication in Laravel.
Install the package using the below command:
composer require laravel/socialite
Also, migrate the tables using this command:
php artisan migrate
Step 5: Create a Twitter Developer Application
To authenticate with Twitter and use its API, we must create a developer application from their developer portal.
Sign up for the Twitter Developer Portal.
After signin up, you need to create an Application for your project like this:
After naming your app, the next step is “Keys and Tokens” like this:
After this, our application was created.
The next step is to set up User Authentication Settings.
In the next step, we will set up the permission for our Twitter developer application.
Now, you need to add a callback URI like this:
Also, you need to add a Privacy policy and Terms of Services URL like this:
We need to add a Terms of Service and Privacy policy because we need the User’s email to save it into our database. We cannot get an email in the response if we don’t provide these two URLs. Save this configuration.
Step 6: Adding Twitter credentials to the .env file
Earlier, we got the API Key and API Secret for our application.
Add both keys to the .env file like this:
TWITTER_CLIENT_ID=xxxxx [Your client id] TWITTER_CLIENT_SECRET=xxxx [your client secret] CALLBACK_URI=http://localhost:8000/auth/callback
Now, open the config/services.php file and add the below configurations:
'twitter' => [ 'client_id' => env('TWITTER_CLIENT_ID'), 'client_secret' => env('TWITTER_CLIENT_SECRET'), 'redirect' => env('CALLBACK_URI'), ],
Step 7: Modify the users table
We must modify the existing users table in the database by adding a “twitter_id” column.
php artisan make:migration add_twitter_id_to_users
Add the column like this:
<?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; return new class extends Migration { /** * Run the migrations. */ public function up(): void { Schema::table('users', function (Blueprint $table) { $table->string('twitter_id')->after('remember_token')->nullable()->unique(); }); } /** * Reverse the migrations. */ public function down(): void { Schema::table('users', function (Blueprint $table) { $table->dropColumn('twitter_id'); }); } };
Run this migration to add a column to the users table:
php artisan migrate
Step 8: Add a twitter_id to the User.model file
In the User.php model file, you must add twitter_id to the $fillable property.
<?php namespace App\Models; // use Illuminate\Contracts\Auth\MustVerifyEmail; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; use Laravel\Fortify\TwoFactorAuthenticatable; use Laravel\Jetstream\HasProfilePhoto; use Laravel\Sanctum\HasApiTokens; class User extends Authenticatable { use HasApiTokens; use HasFactory; use HasProfilePhoto; use Notifiable; use TwoFactorAuthenticatable; /** * The attributes that are mass assignable. * * @var array<int, string> */ protected $fillable = [ 'name', 'email', 'password', 'twitter_id' ]; /** * The attributes that should be hidden for serialization. * * @var array<int, string> */ protected $hidden = [ 'password', 'remember_token', 'two_factor_recovery_codes', 'two_factor_secret', ]; /** * The accessors to append to the model's array form. * * @var array<int, string> */ protected $appends = [ 'profile_photo_url', ]; /** * Get the attributes that should be cast. * * @return array<string, string> */ protected function casts(): array { return [ 'email_verified_at' => 'datetime', 'password' => 'hashed', ]; } }
Step 9: Create a TwitterController
To create a controller, use this command:
php artisan make:controller TwitterController
This TwitterController.php will have two basic functions:
- redirectToTwitter(): This will redirect to the Twitter app for authentication
- handleTwitterCallback(): This will callback to our app after successful authentication
Here is the complete TwitterController.php file:
<?php namespace App\Http\Controllers; use App\Models\User; use Illuminate\Http\RedirectResponse; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Hash; use Illuminate\Support\Str; use Laravel\Socialite\Facades\Socialite; use Throwable; class TwitterController extends Controller { /** * Redirect to Twitter for authentication. * * @return RedirectResponse */ public function redirectToTwitter(): RedirectResponse { return Socialite::driver('twitter')->redirect(); } /** * Handle Twitter authentication callback. * * @return RedirectResponse */ public function handleTwitterCallback(): RedirectResponse { try { $twitterUser = Socialite::driver('twitter')->user(); } catch (Throwable $e) { return redirect()->route('login')->with('error', 'Twitter authentication failed.'); } // Retrieve user from the database by twitter_id or create a new user $user = User::firstOrCreate( ['twitter_id' => $twitterUser->id], [ 'name' => $twitterUser->name, 'email' => $twitterUser->email, 'password' => Hash::make(Str::random(16)) ] ); // Login the user Auth::login($user, true); // Remember the user return redirect()->intended('dashboard'); } }
Basically, in this code, first, we redirect a user to the Twitter application where they enter their email and password, and after it verifies, it returns a callback, which is our callback URI, and from then, we will save the username, email, and password and login the user in our application.
Step 10: Register the routes
Add the below code inside the routes/web.php file:
<?php use Illuminate\Support\Facades\Route; use App\Http\Controllers\TwitterController; Route::get('/', function () { return view('welcome'); }); Route::middleware([ 'auth:sanctum', config('jetstream.auth_session'), 'verified', ])->group(function () { Route::get('/dashboard', function () { return view('dashboard'); })->name('dashboard'); }); Route::controller(TwitterController::class)->group(function () { Route::get('auth/direct', 'redirectToTwitter')->name('auth.twitter'); Route::get('auth/callback', 'handleTwitterCallback'); });
Step 11: Add the link to the login.blade.php file
Add the following code inside resources/views/auth/login.blade.php file.
<x-guest-layout> <x-authentication-card> <x-slot name="logo"> <x-authentication-card-logo /> </x-slot> <x-validation-errors class="mb-4" /> @session('status') <div class="mb-4 font-medium text-sm text-green-600"> {{ $value }} </div> @endsession <form method="POST" action="{{ route('login') }}"> @csrf <div> <x-label for="email" value="{{ __('Email') }}" /> <x-input id="email" class="block mt-1 w-full" type="email" name="email" :value="old('email')" required autofocus autocomplete="username" /> </div> <div class="mt-4"> <x-label for="password" value="{{ __('Password') }}" /> <x-input id="password" class="block mt-1 w-full" type="password" name="password" required autocomplete="current-password" /> </div> <div class="block mt-4"> <label for="remember_me" class="flex items-center"> <x-checkbox id="remember_me" name="remember" /> <span class="ms-2 text-sm text-gray-600">{{ __('Remember me') }}</span> </label> </div> <div class="flex mt-4 justify-between"> <a href="{{ route('auth.twitter') }}" style="padding: 10px 20px; background-color: #1DA1F2; color: white; text-decoration: none; border-radius: 5px; font-weight: bold; box-shadow: 0 2px 4px rgba(0,0,0,0.2); transition: background-color 0.3s ease;"> Login with X / Twitter </a> </div> <div class="flex items-center justify-end mt-4"> @if (Route::has('password.request')) <a class="underline text-sm text-gray-600 hover:text-gray-900 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" href="{{ route('password.request') }}"> {{ __('Forgot your password?') }} </a> @endif <x-button class="ms-4"> {{ __('Log in') }} </x-button> </div> </form> </x-authentication-card> </x-guest-layout>
Save this file and now go to this URL: http://localhost:8000/login
If you click on the Login with X / Twitter button, you will be redirected like this:
If you provide the correct credentials, it will take time for 3-4 seconds, and then it will redirect to http://localhost:8000/dashboard as a logged-in user.
Here is the complete Github Code.
That’s all!