Authenticate With Any OAuth Provider With Laravel Socialite

Authenticate With Any OAuth Provider With Laravel Socialite

Given Ncube

Ever tried to create an account on a website and find out there's no option to "login with Google"? Annoying, right? You're not alone. Luckily for you I can help you prevent that and get more signups for your app

In this post I will show you how to create a universal Socialite Controller that works for any socialite driver

To get start, let's install socialite with composer on a Laravel pronect

composer require laravel/socialite

So the way socialite works is that a user clicks on a link that redirects them to a 3rd party site to login and then redirected back to your site for the actual login.

So first, let's create the socialite controller

php artisan make:controller SocialiteController

Redirect

So this is when we redirect the user to 3rd party OAuth provider to login. Add this method to the SocialiteController

/**
 * @param string $driver
 * @return RedirectResponse
 */
public function redirect(string $driver): RedirectResponse
{
    return Socialite::driver($driver)->redirect();
}

So the redirect takes a $driver as an argument so we can add any driver any time. Say, you had used Google before, and now you want add GitHub, you just change a route parameter

Callback

After the user is logged in, they are redirected to a callback URI that does the actual login. Add the following method to the controller

/**
 * @param string $driver
 * @return RedirectResponse
 */
public function callback(string $driver): RedirectResponse
{
    try {
        $socilite = Socialite::driver($driver)->user();
    } catch (Exception) {
        return to_route('login')->with('error', 'Something went during. Please try again.');
    }

    $user = User::whereEmail($socilite->getEmail())->first();

    if (is_null($user)) {
        $user = User::create([
            'name' => $socilite->getName(),
            'email' => $socilite->getEmail(),
            'password' => Hash::make($socilite->getId()),
        ]);

        event(new Registered($user));
    }

    auth()->login($user, true);
    session()->regenerate();

    return redirect()->intended(RouteServiceProvider::HOME);
}

This method also takes the $driver as an argument to tell socialite which provider was used login.

If for some reason something went wrong, we redirect the user to the login page with a flash error message

We then check if the user has an existing account, if not, we create an new one with a random password which they can change later from the profile page if they so wish

Else, we log them in and regenerate session to prevent session high jacking by bad actors

Finally we redirect the user to the intended URL

Routes

To make this work, we need to register the routes for this controller

Route::get('/auth/{driver}/redirect', [SocialiteController::class, 'redirect'])
    ->name('socialite.redirect')
    ->whereIn('driver', ['google']);

Route::get('/auth/{driver}/callback', [SocialiteController::class, 'callback'])
    ->name('socialite.callback')
    ->whereIn('driver', ['google']);

Here we add {driver} as a route parameter which will be injected into the callback and redirect method thanks to Laravel's Dependncy Injection.

Say a bad actor realizes that the {driver} parameter is dynamic, and tries other characters like a social driver that does not exist, that could have unwanted side effects.

To prevent this, we call the whereIn() method and tell Laravel to expect only a defined set of values for the driver param, in this case just "google". Anything else besides that will throw a 404 Not Found.

Socialite authenticate with Google

Our code is ready for use, in production! In this example, let's allow users to login to our app using their google accounts.

First, get credentials from Google Cloud Console

Step 1, visit https://console.cloud.google.com and signin with your google account

Step 2, Create a new project or use an existing one

Step 3, Click the 3bar menu and select APIs & Services > Credentials

image

Step 4, Click on Create Credentials > OAuth Client ID

Step 5, Select Web Application from the dropdown and enter name and redirect URIs

image

On the redirect URI this is where you put the link to your callback route replace the {driver} param with "google". For example http://localhost:8000/auth/google/callback

Now all that is left is just creating a link that your users can click to login with Google. For example if you have a Breeze Starter kit installed

<a href='{{ route('socialite.redirect', 'google') }}'>
    <x-secondary-button aria-label="Continue with google"
                        class="w-full justify-center mt-5">
        <img src="https://tuk-cdn.s3.amazonaws.com/can-uploader/sign_in-svg2.svg"
             alt="google">
        <p class="text-base font-medium ml-4 text-gray-700">Continue with Google</p>
    </x-secondary-button>
</a>

I hope this helps you to create more smooth login flows for your apps. To make sure you don't miss another tutorial like this when it's up, follow me here on DEV and get a ping each time I make a new post.

I regularly post helpful laravel tuts like this, subscribe to the newsletter below and get notified when it's publish the next one