Laravel Nova: Implementing Social Logins
Tags: php, laravel, development
Published: 2020-01-21 11:15:49

---
title: Laravel Nova: Implementing Social Logins
published: true
date: 2020-01-14 21:30:45 UTC
tags: php,laravel,development
canonical_url: 
---

![](https://cdn-images-1.medium.com/max/1024/0*IlImmFoo9ervClwS)<figcaption>Photo by <a href="https://unsplash.com/@dsmacinnes?utm_source=medium&amp;utm_medium=referral">Danielle MacInnes</a> on <a href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption>

[_Laravel Nova_](https://nova.laravel.com/) has been available for over a year now and I’ve been pleasantly surprised by just how extensible it is despite the documentation sometimes being a bit brief. Since working for [_Trade Cover Exchange_](http://www.tradecoverexchange.com) I’ve had to work on a couple features with Nova and one of them was a security feature, social logins. You might ask how social logins are a security feature for Laravel Nova and the simple answer is [_Google G-Suite_](https://gsuite.google.co.uk/intl/en_uk/). At Trade Cover Exchange there’s less than 5 employees so having a way of managing that access to admin areas is really important. A company using Google G-suite might want to control which users can login to their Nova application based on them having email addresses managed via G-Suite, then you can secure more things by forcing the G-Suite account to have to use two factor authentication to login.

In starting this project I’m going to assume that you already have a working Laravel Nova project that you can add to. You don’t need a G-Suite set up to follow this guide but you might need to tweak things to make it work securely and how you want to.

### Install Socialite

If you don’t know already, Laravel has a social login package called [_Socialite_](https://laravel.com/docs/6.x/socialite) which is normally used for social logins and it can be used in exactly the same way for Laravel Nova.

To install socialite we use the following composer command:

```
composer require laravel/socialite
```

Then we simply need to setup a google cloud project with an oauth client. You can read about social logins and set one up from this [piece of documentation](https://developers.google.com/identity/sign-in/web/sign-in). When it asks for the callback URL we’re just going to use [http://localhost/nova/google/callback](http://localhost/nova/google/callback). Once we’ve done that we can add the newly generated client ID and secret to our .env file.

```
GOOGLE_CLIENT_ID_=<YOUR CLIENT ID>
GOOGLE_CLIENT_SECRET=<YOUR CLIENT SECRET>
```

We also need to add the following to our config/services.php file to work with Socialite using the environment variables we just added to the env file.

```
'google' => [
    'client_id' => env('GOOGLE_CLIENT_ID'),
    'client_secret' => env('GOOGLE_CLIENT_SECRET'),
    'redirect' => '/nova/google/callback',
],
```

### Creating our Login Page

The next step is a fairly simple one. We’re going to just create a new login view which will override the normal one and instead it’ll show a simple _Sign In_ button instead of a typical login form with email and password fields.

We create this file at resources/views/vendor/nova/auth/login.blade.php with the following content. This will override the default login page for the nova package. You might want to look it over and customise the line mentioning what accounts you can use.

{% gist https://gist.github.com/peterfox/f3f15bbdd819ff5368d7e44a88828b1e %}

### Adding a social controller

We need a very simple controller to handle the different methods required for handling the social authentication.

In this controller we’ll have two accessible routes as we normally would for _Laravel Socialite_. First one to redirect to Google to perform the authorisation and other to simply handle the callback once the user has been authorised.

To redirect to Google we’ll create a method called redirectToGoogle which will call the Google socialite driver. We’ll also add an extra option called hd which the value is going to be our G-Suite domain. This simply means we can tell Google to display the domain on our authorisation page. This will save the user from typing out their full email address. The code looks like this:

```
public function redirectToGoogle()
{
return Socialite::driver('google')
        // Displays the G-Suite domain saving the user from typing their whole  
        // email address.
        ->with(['hd' => 'ylsideas.co'])
        ->redirect();
}
```

Our next method is then performing the callback once a user has authenticated with Google. What we’ll do is grab the user from the Google socialite driver and check is the user’s email address returned matches our domain.

After these checks we’ll perform a firstOrCreate call on the User model. This means that a first time user will be created if they don’t exist or we’ll fetch it from the database should they already exist, using the email address as the unique key.

Our next step is to pass the new user to the Auth guard and create a logged in session for the user.

After this we can redirect the user back to the intended path or simply to the home page.

Our code for the method should look like this:

```
public function processGoogleCallback(Request $request)
{
try {
        $socialUser = Socialite::driver('google')->user();
    } catch (InvalidStateException $exception) {
return redirect()->route('nova.login')
            ->withErrors([
                'email' => [
                    __('Google Login failed, please try again.'),
                ],
            ]);
    }

// Very Important! Stops anyone with any google accessing Nova!  
    if (! Str::endsWith($socialUser->getEmail(), 'ylsideas.co')) {
return redirect()->route('nova.login')
            ->withErrors([
                'email' => [
                    __('Only ylsideas.co email addresses are accepted.'),
                ],
            ]);
    }

    $user = User::firstOrCreate(
        ['email' => $socialUser->getEmail()],
        [
            'name' => $socialUser->getName(),
            'password' => Str::random(32),
        ]
    );

    $this->guard()->login($user);

return redirect()->intended(Nova::path());
}
```

Take note in the processGoogleCallback that in the event the first two checks fail then the user is directed back to the original login page with an error that can be displayed on the page making it clear to the end user why the login has failed.

If you need the full file you can view it below:

{% gist https://gist.github.com/peterfox/2f3ffc0508f2b6dade28fd795e4c6a6d %}

### Setting up the Routes

Now we’ve built the controller we only need to tweak a few lines in the NovaServiceProvider and add our new routes for accessing the SocialLoginController we created in the last step.

We can do this by replacing the contents of the NovaServiceProvider’s routes method with the example below.

{% gist https://gist.github.com/peterfox/f21f476227a7146ee6a0c7f25445ebc1 %}

This will remove the registration, password reset and login routes. Instead we add our own login routes which will make use the the SocialLoginController we made in the last step.

### Testing it out

It should be fairly easy to quickly test this out. If you simply go to the /nova/login page of your site it should direct you to the new login page which looks a little like this:

![screenshot of the social login page for nova](https://cdn-images-1.medium.com/max/1024/1*r2DBt22qLOiy03CM-ytBJA.png)

Then when you click the sign in button it’ll take you to a google page. After completing the authorisation process you’ll then be directed back to the application and onto the home screen.

If you just want to see the whole project together you can [view it on github](https://github.com/peterfox/nova-social-login-demo).

I’m Peter Fox, a software developer in the UK who works with Laravel among other things. If you want to know more about me you can at [https://www.peterfox.me](https://www.peterfox.me/) and feel free to follow me @[SlyFireFox](https://twitter.com/SlyFireFox) on twitter for more Laravel tips and tutorials.

* * *