← Back
May 12, 2026

Discord OAuth in Laravel - the guide I wish existed

Discord OAuth should be straightforward. Socialite exists, there's a community Discord provider, the pieces are all there. And yet the first time I wired it up for Galaxy Community, I spent two hours filling gaps the docs quietly skipped over.

The setup

Install Socialite and the Discord provider:

composer require laravel/socialite socialiteproviders/discord

Register the provider in your AppServiceProvider:

// app/Providers/AppServiceProvider.php
use SocialiteProviders\Discord\Provider;
use Laravel\Socialite\Contracts\Factory;

public function boot(): void
{
    $socialite = $this->app->make(Factory::class);
    $socialite->extend('discord', fn ($app) =>
        $socialite->buildProvider(Provider::class, config('services.discord'))
    );
}

Add your credentials to config/services.php:

'discord' => [
    'client_id'     => env('DISCORD_CLIENT_ID'),
    'client_secret' => env('DISCORD_CLIENT_SECRET'),
    'redirect'      => env('DISCORD_REDIRECT_URI'),
],

The routes and controller

// routes/web.php
Route::get('/auth/discord',          [AuthController::class, 'redirect']);
Route::get('/auth/discord/callback', [AuthController::class, 'callback']);
// AuthController.php
public function redirect()
{
    return Socialite::driver('discord')->redirect();
}

public function callback()
{
    $discordUser = Socialite::driver('discord')->user();

    $user = User::updateOrCreate(
        ['discord_id' => $discordUser->getId()],
        [
            'name'   => $discordUser->getName(),
            'email'  => $discordUser->getEmail(),
            'avatar' => $discordUser->getAvatar(),
        ]
    );

    Auth::login($user, remember: true);
    return redirect()->intended('/dashboard');
}

The part the docs skip

By default the email scope isn't requested. If you need the user's email - and you probably do - ask for it explicitly:

return Socialite::driver('discord')
    ->scopes(['identify', 'email'])
    ->redirect();

Also make sure your Discord application's redirect URI matches exactly - trailing slash and all. Discord will silently reject mismatches with a generic error that tells you nothing useful.

next post →

Laravel + React without the API tax