Muhammad Yasir Amin

Loading websiteโ€ฆ

More from Muhammad Yasir Amin

Build Along With Me

Practical walkthroughs on Laravel, React, APIs and deployment workflows.

Subscribe on YouTube

Laravel 13 Socialite Login with X (Twitter): Step-by-Step Tutorial

๐Ÿ› ๏ธ Laravel Tutorials4 min read

Laravel 13 Socialite Login with X (Twitter): Step-by-Step Tutorial

Muhammad Yasir Amin

Muhammad Yasir Amin

Senior Full Stack Engineerโ€ขNov 12, 2026
Laravel 13 Socialite Login with X (Twitter): Step-by-Step Tutorial

To add Login with X (formerly Twitter) to Laravel 13, install Socialite, create an app in the X developer portal, add its keys under the x key in config/services.php and write a redirect route and a callback route. A key detail: X does not always return an email address, so your user table and callback code must work without one. This tutorial shows the full flow.

Targets: Laravel 13 (PHP 8.3 to 8.5) and laravel/socialite. In current Socialite versions the driver for this network is named x.

Step 1: Install Socialite

Code
composer require laravel/socialite

Step 2: Create an app in the X developer portal

  1. Sign in to the X developer portal and create a project and an app.
  2. Open the app's user authentication settings and enable OAuth 2.0.
  3. Choose the app type Web App (a confidential client).
  4. Add your callback URL, for example http://localhost:8000/auth/x/callback.
  5. Copy the Client ID and Client Secret.

Portal screens and plan names change often, so follow the labels you see. The callback URL must match your configuration exactly.

Step 3: Add the credentials

Code
X_CLIENT_ID=your-client-id
X_CLIENT_SECRET=your-client-secret
X_REDIRECT_URI=http://localhost:8000/auth/x/callback
JavaScript
'x' => [
    'client_id' => env('X_CLIENT_ID'),
    'client_secret' => env('X_CLIENT_SECRET'),
    'redirect' => env('X_REDIRECT_URI'),
],

Add the array to config/services.php.

Step 4: Prepare the users table

Because X users may have no email, the users.email column needs to allow null, or you must create a placeholder address. This tutorial makes the email nullable and stores the X ID separately:

Code
php artisan make:migration add_x_id_to_users_table --table=users
JavaScript
public function up(): void
{
    Schema::table('users', function (Blueprint $table) {
        $table->string('x_id')->nullable()->unique()->after('email');
        $table->string('email')->nullable()->change();
        $table->string('password')->nullable()->change();
    });
}

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

Run php artisan migrate and add x_id to the $fillable list of the User model. Changing the email column to nullable can affect other parts of your app, such as password reset, so decide whether that is acceptable for your project.

Step 5: Write the controller

JavaScript
<?php

namespace App\Http\Controllers;

use App\Models\User;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Str;
use Laravel\Socialite\Facades\Socialite;
use Throwable;

class XAuthController extends Controller
{
    public function redirect(): RedirectResponse
    {
        return Socialite::driver('x')->redirect();
    }

    public function callback(): RedirectResponse
    {
        try {
            $xUser = Socialite::driver('x')->user();
        } catch (Throwable $e) {
            report($e);

            return redirect('/login')->withErrors(['email' => 'Login with X failed. Please try again.']);
        }

        $user = User::updateOrCreate(
            ['x_id' => $xUser->getId()],
            [
                'name' => $xUser->getName() ?: $xUser->getNickname() ?: 'X user',
                'email' => $xUser->getEmail(),
                'password' => Str::password(32),
            ]
        );

        Auth::login($user, remember: true);

        return redirect()->intended('/dashboard');
    }
}

The lookup key is the X ID, never the email. updateOrCreate runs the update part on every login, so a nullable email is simply stored as null when X does not provide one. If you must have an email, redirect users without one to a form that asks for it.

Step 6: Routes and button

CSS
use App\Http\Controllers\XAuthController;
use Illuminate\Support\Facades\Route;

Route::get('/auth/x/redirect', [XAuthController::class, 'redirect'])->name('x.redirect');
Route::get('/auth/x/callback', [XAuthController::class, 'callback']);
HTML / XML
<a href="{{ route('x.redirect') }}">Continue with X</a>

How do I test the login?

  1. Start the app and click the X link.
  2. Authorize the app with your own X account.
  3. Check that you are redirected to /dashboard and that a user row with an x_id exists.

Common mistakes

  • Using the old twitter driver name: current Socialite documents the key as x. Use that name in services.php and in Socialite::driver().
  • Expecting an email: X may not return one, so do not use email as the identity.
  • Callback URL mismatch: update the portal, .env and your route together.
  • App without user authentication enabled: the OAuth screen fails until you enable OAuth 2.0 in the app settings.
  • Stale config: run php artisan config:clear after changing the credentials.

FAQ

Is the Twitter driver still supported?

Laravel's Socialite documentation lists X as the provider and uses the x configuration key. Check the documentation for your installed version.

Can I get the user's avatar?

Yes. The returned user object has getAvatar(). Store the URL if you need it.

Do I need the stateless() method?

Only for stateless apps without sessions. Regular web apps use the default flow.

References

Article Index & Topic Tags
LaravelSocialiteAuthenticationX

YouTube Channel

Build Along With Me

Practical walkthroughs on Laravel, React, APIs and deployment workflows.

Muhammad Yasir Amin
Available for Contracts
Author & Solutions Architect

Senior Full Stack Engineer

Independent Senior Full Stack Engineer working on Laravel, React and Next.js applications, APIs and delivery workflows.

Laravel & PHP ApplicationsReact & Next.js InterfacesREST APIs & IntegrationsDatabase Queries & DebuggingDocker Development WorkflowsClear Scope & Handover
Discuss Your Next Step

What Does Your Application Need Next?

Share your current system, the problem you want to solve and what a useful result looks like. We can identify the right starting point and agree on a practical scope.

Technical Audit

Find the Next Useful Fix

Application Development

Scoped, Reviewable Milestones

Ongoing Support

Agreed Capacity and Priorities

Share your goals, current stack and requirements before the call.