Adding Authentication(Auth0) to Your Laravel 7 Application
Tags: auth0, laravel, laravel7, php
Published: 2020-03-29 16:29:52

[Laravel](www.laravel.com) is a free, open-source PHP web framework, intended for the development of web applications following the `model–view–controller` architectural pattern for companies and developers all over the world.

In this tutorial, I'll show you how to build a web application with [Laravel 7](https://laravel.com/) and add authentication with [Auth0](https://auth0.com/).

We'll be building a simple listing app with Laravel 7. Our app will simply list the last 10 UEFA Champions League winners' names with the scoreline. Once we add authentication to the app, all logged-in users will have the privilege of knowing the winner along with the scoreline.

![UnAuthenticated App](https://dev-to-uploads.s3.amazonaws.com/i/w37om6f3oswl28h9scii.png)
![Authenticated App](https://dev-to-uploads.s3.amazonaws.com/i/ftp6h2t9ok9vxed3u012.png)

#### **Let's Get Started**
Laravel utilizes [Composer](http://getcomposer.org/) to manage its dependencies. And I assume, you have already installed it and are ready to go. If not, please install from [here](http://getcomposer.org/). Once Composer is installed, we can install Laravel by issuing the Composer `create-project` command in your terminal like so:

![composer create-project --prefer-dist laravel/laravel UEFA](https://dev-to-uploads.s3.amazonaws.com/i/68wu32g5zbiz0g05qwiu.png)

Now run the following in your terminal to launch your application:
```bash
$ php artisan serve
```

Laravel applications follow the **Model-View-Controller** design pattern.

  * **Models** query your database and return the necessary data.
  * **Views** are the pages that render data.
  * **Controllers** handles user requests, retrieves data from the models, and passes them to the views.

#### **Setting Up The Controller**
Open up your terminal and in the project root directory, run the command below to create a `ListController`.

```bash
php artisan make:controller ListController
```
Open up `app/Http/Controllers/ListController.php` and configure it like so:

```php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class ListController extends Controller
{
    public function show()
    {

       $uefa = [
        '2018-19' => ['winner' => 'Liverpool', 'played' => 'Liverpool V Tottenham Hotspur', 'score' => '2-0'],
        '2017-18' => ['winner' => 'Real Madid', 'played' => 'Real Madrid V Liverpool', 'score' => '3-1'],
        '2016-17' => ['winner' => 'Real Madid', 'played' => 'Real Madrid V Juventus', 'score' => '4-1'],
        '2015-16' => ['winner' => 'Real Madid', 'played' => 'Real Madrid V Athletico Madid', 'score' => '1*-1'],
        '2014-15' => ['winner' => 'Barcelona', 'played' => 'Barcelona V Juventus', 'score' => '3-1'],
        '2013-14' => ['winner' => 'Real Madid', 'played' => 'Real Madrid V Athletico Madid', 'score' => '4-1'],
        '2012-13' => ['winner' => 'Bayern Munich', 'played' => 'Bayern Munich V Borussia Dortmund', 'score' => '4-1'],
        '2011-12' => ['winner' => 'Chelsea', 'played' => 'Chelsea V Bayern Munich', 'score' => '4-1'],
        '2010-11' => ['winner' => 'Barcelona', 'played' => 'Manchester United V Barcelona', 'score' => '4-1'],
        '2009-10' => ['winner' => 'Internazionale', 'played' => 'Bayern Munich V Internazionale', 'score' => '4-1'],
       ];

       return view('welcome')->withUefa($uefa);
    }
}

```

`view('welcome')->withUefa($uefa)` indicates that we are passing the $uefa array to a view called welcome.blade.php. We'll see that view later in this post.

#### **Setting Up The Routes**
Open up `routes/web.php` and configure it like this:
```php
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

Route::get('/', 'ListController@show');
```
Once a request hits the `/` route, it invokes the `show` method of the `ListController` and renders the returned value in the `welcome` view.

#### **Setting Up Authentication**
We're going to be using [Auth0](www.auth0.com) for authentication. Setting up the built-in authentication with Laravel is pretty straightforward, but limited. With Auth0, you'll have access to an easy-to-use dashboard, the ability to integrate social identity providers, two-factor authentication, passwordless login, and much more. 

***Auth0 vs Laravel's Built-in Authentication***
Laravel comes with [out-of-the-box authentication](https://laravel.com/docs/7.x/authentication) that can be set up with just a bit of configuration. But with Laravel 7, it's a bit more steps.
First, you need to install `laravel/ui` using composer
```bash
composer require laravel/ui
```
Once the `laravel/ui` package has been installed, you may install the frontend scaffolding using the ui Artisan command:
```bash
php artisan ui bootstrap --auth
php artisan ui vue --auth
php artisan ui react --auth
```

**So why use Auth0 instead?**
[Auth0](www.auth0.com) comes with all of these options, most of which you can enable with just a click from the dashboard:
  * Universal login from a centralized authorization server
  * Social login (Facebook, Twitter, GitHub, etc.)
  * Easily manage users from the dashboard
  * Multi-factor authentication
  * Easy role management
  * Brute force protection
  * Breached password detection
  * Account linking for users who need to merge two separate accounts
  * Option to block certain users
  * Advanced user login analytics
  * Extend Auth0 capabilities with custom rules
  * [And much more!](https://auth0.com/why-auth0)

Perhaps the greatest benefit of all is being able to shift the stress of securing your application against the never-ending threat of attacks onto someone else!

_**Signing up for Auth0**_
Let's see how easy it is to integrate Auth0 into your Laravel 7 application. If you don't already have an account, go ahead and [sign up for a free Auth0 account](https://auth0.com/signup) now.

Once you've signed up, click on ["Applications"](https://manage.auth0.com/#/applications) on the dashboard. There will be a default application, but you need to create one with the name "Laravel 7 App" or anything you'd like, with type "Regular Web Application".
![Auth0 Dashboard](https://dev-to-uploads.s3.amazonaws.com/i/hj8xxxjf2bnwu43nlyd1.jpg)
![Create Laravel 7 App with Regular Web App](https://dev-to-uploads.s3.amazonaws.com/i/2pj7g9iygeeoy6hd7q9g.jpg)

Update these values as follows:
  * Allowed Callback URLs: `http://localhost:8000/auth0/callback` or `http://homestead.test/auth0/callback`
  * Allowed Logout URLs: `http://localhost:8000` or `http://homestead.test`
Just make sure it matches exactly what your development URL is, no trailing slashes.

![Callaback-Logout-URLs](https://dev-to-uploads.s3.amazonaws.com/i/bpppbczsvx4vq4oek8ly.png)

**Install the Auth0 PHP plugin**
Now go back to your terminal and install the Auth0 plugin and dependencies.
```bash
composer require auth0/login:"~5.0"
```
This will install the Auth0 PHP plugin and Auth0 Laravel plugin.

**Finishing up Auth0 integration**
Next, open up the `config/app.php` file and add the Auth0 login service provider to the list of providers:
```php
// ...
'providers' => [
    // ...
    Auth0\Login\LoginServiceProvider::class,
];
```

Scroll down in that same file until you find the aliases array and then add the Auth0 facade:

```php
// ...
'aliases' => [
    // ...
    'Auth0' => Auth0\Login\Facade\Auth0::class,
];
```

Now you'll bind the `Auth0UserRepository` class that provides the `User` model every time a user is logged in or a JWT is decoded. Open up `app/Providers/AppServiceProvider.php` and add the following under `register()`:
```php
// ...
class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        $this->app->bind(
        \Auth0\Login\Contract\Auth0UserRepository::class,
        \Auth0\Login\Repository\Auth0UserRepository::class
        );
    }

    // ...
}
```

Now head back to the terminal to publish the plugin configuration. You'll run the following command and then it will ask you which vendor file you'd like to publish.
```bash
php artisan vendor:publish
```
Select `Auth0\Login\LoginServiceProvider` from the resulting list, which will create the `config/laravel-auth0.php` configuration file.

**laravel-auth0.php**
```php
<?php

return [

    /*
    |--------------------------------------------------------------------------
    |   Your auth0 domain
    |--------------------------------------------------------------------------
    |   As set in the auth0 administration page
    |
    */
    'domain'        => env( 'AUTH0_DOMAIN' ),

    /*
    |--------------------------------------------------------------------------
    |   Your APP id
    |--------------------------------------------------------------------------
    |   As set in the auth0 administration page
    |
    */
    'client_id'     => env( 'AUTH0_CLIENT_ID' ),

    /*
    |--------------------------------------------------------------------------
    |   Your APP secret
    |--------------------------------------------------------------------------
    |   As set in the auth0 administration page
    |
    */
    'client_secret' => env( 'AUTH0_CLIENT_SECRET' ),

    /*
     |--------------------------------------------------------------------------
     |   The redirect URI
     |--------------------------------------------------------------------------
     |   Should be the same that the one configure in the route to handle the
     |   'Auth0\Login\Auth0Controller@callback'
     |
     */
    'redirect_uri'  => env( 'APP_URL' ) . ':8000/auth0/callback',

    /*
    |--------------------------------------------------------------------------
    |   Persistence Configuration
    |--------------------------------------------------------------------------
    |   persist_user            (Boolean) Optional. Indicates if you want to persist the user info, default true
    |   persist_access_token    (Boolean) Optional. Indicates if you want to persist the access token, default false
    |   persist_refresh_token   (Boolean) Optional. Indicates if you want to persist the refresh token, default false
    |   persist_id_token        (Boolean) Optional. Indicates if you want to persist the id token, default false
    |
    */
    'persist_user' => true,
    'persist_access_token' => false,
    'persist_refresh_token' => false,
    'persist_id_token' => false,

    /*
    |--------------------------------------------------------------------------
    |   The authorized token issuers
    |--------------------------------------------------------------------------
    |   This is used to verify the decoded tokens when using RS256
    |
    */
    'authorized_issuers'  => [ env( 'AUTH0_DOMAIN' ) ],

    /*
    |--------------------------------------------------------------------------
    |   The authorized token audiences
    |--------------------------------------------------------------------------
    |
    */
    // 'api_identifier'  => '',

    /*
    |--------------------------------------------------------------------------
    |   The secret format
    |--------------------------------------------------------------------------
    |   Used to know if it should decode the secret when using HS256
    |
    */
    'secret_base64_encoded'  => false,

    /*
    |--------------------------------------------------------------------------
    |   Supported algorithms
    |--------------------------------------------------------------------------
    |   Token decoding algorithms supported by your API
    |
    */
    'supported_algs'        => [ 'RS256' ],

    /*
    |--------------------------------------------------------------------------
    |   Guzzle Options
    |--------------------------------------------------------------------------
    |   guzzle_options    (array) optional. Used to specify additional connection options e.g. proxy settings
    |
    */
    // 'guzzle_options' => []
];

```
A few of these need to be filled in, but you want to keep them out of the repository since this is sensitive information. This is done using the `.env` file.

Open up `.env` and add the following:
```
AUTH0_DOMAIN=your-auth0-domain.auth0.com
AUTH0_CLIENT_ID=your-client-id
AUTH0_CLIENT_SECRET=your-client-secret
```

All of these values can be found in your Auth0 dashboard under "Applications" > "Your Application" > "Settings".

![ClientID](https://dev-to-uploads.s3.amazonaws.com/i/82jhs54fpkuqzm5ujv8o.jpg)

Next, take a look at what's set for `APP_URL`. It should match the URL that you've been using for your application, which is most likely `http://homestead.test` or `http://localhost:8000`. If you're using `http://localhost:8000`, make sure the port is included here! It is most likely in the top of the `.env` file, please don't create a new entry for this.

```
APP_URL=http://localhost:8000
```

**Integrate Auth0 with Laravel authentication system**
Next, the Auth0 plugin needs to be integrated with the Laravel authentication system.

The Laravel authentication system needs a `User Object` from the User Provider so that it can know how user data is structured and where it is stored. This is configured in `config/auth.php`. The default provider is `Eloquent`, which will persist the `User` model in the database using the Eloquent ORM. For this application, we're not using the default `User` model.

Because our user data will be stored in Auth0's database, the Auth0 plugin comes with its own authentication driver that defines the user based on a standardized user profile instead of Laravel's `User` model.

To switch out the user driver, open up `config/auth.php` and change it to this:
```php
// ...
'providers' => [
    'users' => [
        'driver' => 'auth0',
    ],
],
```

**Setup authentication routes**
Open `routes/web.php` and add these authentication routes:
```php
Route::get( '/auth0/callback', '\Auth0\Login\Auth0Controller@callback' )->name( 'auth0-callback' );  
Route::get( '/login', 'Auth\Auth0IndexController@login' )->name( 'login' );  
Route::get( '/logout', 'Auth\Auth0IndexController@logout' )->name( 'logout' )->middleware('auth');  
```

This first route is using the `Auth0Controller` provided by the plugin that was installed earlier to handle the callback. If you'd like to take a look at the "magic" occurring here, you can find the controller in `vendor/auth0/login/src/controllers`. The rest of the Auth0 Laravel files lie in `vendor/auth0/login/src/Auth/Login`.

```javascript
/**
    * Callback action that should be called by auth0, logs the user in.
    */
public function callback()
{
    // Get a handle of the Auth0 service (we don't know if it has an alias)
    $service = \App::make('auth0');

    // Try to get the user information
    $profile = $service->getUser();

    // Get the user related to the profile
    $auth0User = $this->userRepository->getUserByUserInfo($profile);

    if ($auth0User) {
        // If we have a user, we are going to log them in, but if
        // there is an onLogin defined we need to allow the Laravel developer
        // to implement the user as they want an also let them store it.
        if ($service->hasOnLogin()) {
            $user = $service->callOnLogin($auth0User);
        } else {
            // If not, the user will be fine
            $user = $auth0User;
        }
        \Auth::login($user, $service->rememberUser());
    }

    return \Redirect::intended('/');
}
```

The next two routes handle the actual login and logout.
```php
Route::get( '/login', 'Auth\Auth0IndexController@login' )->name( 'login' );
Route::get( '/logout', 'Auth\Auth0IndexController@logout' )->name( 'logout' )->middleware('auth');
```

They use a controller called Auth0IndexController, which you need to create now.
```bash
php artisan make:controller Auth/Auth0IndexController
```

Now open up `app/Http/Controllers/Auth/Auth0IndexController.php` and replace it with the following:
```php
<?php

namespace App\Http\Controllers\Auth;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;

class Auth0IndexController extends Controller
{
  /**
    * Redirect to the Auth0 hosted login page
    *
    * @return mixed
    */
  public function login()
  {
    $authorize_params = [
      'scope' => 'openid profile email',
    ];
    return \App::make('auth0')->login(null, null, $authorize_params);
  }

  /**
    * Log out of Auth0
    *
    * @return mixed
    */
  public function logout()
  {
    \Auth::logout();
    $logoutUrl = sprintf(
      'https://%s/v2/logout?client_id=%s&returnTo=%s',
      env('AUTH0_DOMAIN'),
      env('AUTH0_CLIENT_ID'),
      env('APP_URL'));
    return  \Redirect::intended($logoutUrl);
  }
}
```

Then the `login()` function will send users to Auth0 to enter in their credentials. You'll see this in action soon.

The scopes being requested are:

  * `openid` — to indicate that the application intends to use OIDC to verify the user's identity
  * `profile` — returns name, nickname, and picture.
  * `email` — returns email and if the email is verified

The `logout()` function uses those environment variables you set earlier to hit an Auth0 logout URL, redirect back to the logout URL you set in the dashboard, and clear all session data for the user.

Finally, you just need to add the login links to the navigation and display the list of winners.

Open your `welcome.blade.php` and configure it like this:
```php

@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-8">
            <div class="card">
                <div class="card-header">UEFA Winners</div>

                <div class="card-body">
                    @if (session('status'))
                        <div class="alert alert-success" role="alert">
                            {{ session('status') }}
                        </div>
                    @endif

                    <!-- Table -->
                    <table class="table">
                        <thead class="thead-dark">
                            <tr>
                            <th scope="col">Year</th>
                            <th scope="col">Match Played</th>
                            <th scope="col">Winner</th>
                            <th scope="col">Score</th>
                            </tr>
                        </thead>
                        <tbody>
                            @foreach($uefa as $key => $value)
                            <tr>
                            <th scope="row">{{ $key }}</th>
                            <td>{{ $value['played'] }}</td>
                            @if(Auth::user())
                            <td><a href="#" class="btn btn-sm btn-success">{{ $value['winner'] }}</a></td>
                            <td><a href="#" class="btn btn-sm btn-info">{{ $value['score'] }}</a></td>
                            @endif
                            @if(Auth::guest())
                            <td> <a href="/login" class="btn btn-sm btn-warning"> Login to see winner </a> </td>
                            <td> <a href="/login" class="btn btn-sm btn-danger"> SCORE </a> </td>
                            </tr>
                            @endif
                            @endforeach
                        </tbody>
                    </table>
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

```

Here, we are looping through the $uefa array data passed from the ListController for appropriate rendering in the welcome view.

`Auth::user()` — You can check if a user is authenticated or not via this method from the Auth Facade. It returns true if a user is logged-in and false if a user is not.
`Auth::guest()` — This does the opposite of Auth::user(). It returns true if a user is not logged in and false if a user is logged in. 

We are extending the `layouts/app.blade.php` file, for this to work properly, open `layouts/app.blade.php` change it to this:

```php
<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <!-- CSRF Token -->
    <meta name="csrf-token" content="{{ csrf_token() }}">

    <title>{{ config('app.name', 'Laravel') }}</title>

    <!-- Scripts -->
    <script src="{{ asset('js/app.js') }}" defer></script>

    <!-- Fonts -->
    <link rel="dns-prefetch" href="//fonts.gstatic.com">
    <link href="https://fonts.googleapis.com/css?family=Nunito" rel="stylesheet">

    <!-- Styles -->
    <link href="{{ asset('css/app.css') }}" rel="stylesheet">
</head>
<body>
    <div id="app">
        <nav class="navbar navbar-expand-md navbar-light bg-white shadow-sm">
            <div class="container">
                <a class="navbar-brand" href="{{ url('/') }}">
                    {{ config('app.name', 'Laravel') }}
                </a>
                <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="{{ __('Toggle navigation') }}">
                    <span class="navbar-toggler-icon"></span>
                </button>

                <div class="collapse navbar-collapse" id="navbarSupportedContent">
                    <!-- Left Side Of Navbar -->
                    <ul class="navbar-nav mr-auto">

                    </ul>

                    <!-- Right Side Of Navbar -->
                    <ul class="navbar-nav ml-auto">
                        <!-- Authentication Links -->
                        @guest
                            <li class="nav-item">
                                <a class="nav-link" href="{{ route('login') }}">{{ __('Login') }}</a>
                            </li>
                            @if (Route::has('register'))
                                <li class="nav-item">
                                    <a class="nav-link" href="{{ route('register') }}">{{ __('Register') }}</a>
                                </li>
                            @endif
                        @else
                            <li class="nav-item dropdown">
                                <a id="navbarDropdown" class="nav-link dropdown-toggle" href="#" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" v-pre>
                                    {{ Auth::user()->name }} <span class="caret"></span>
                                </a>

                                <div class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarDropdown">
                                    <a class="dropdown-item" href="{{ url('/logout') }}">
                                        {{ __('Logout') }}
                                    </a>
                                </div>
                            </li>
                        @endguest
                    </ul>
                </div>
            </div>
        </nav>

        <main class="py-4">
            @yield('content')
        </main>
    </div>
</body>
</html>

```
If the user is logged in, they'll see the logout button and if not, they'll see the login button.

Now that we have all the routes and views setup, your application should look like this:

_Landing Page_
![Landing Page](https://dev-to-uploads.s3.amazonaws.com/i/n97cls75jqu404jdu4u2.png)

We're using Auth0 for authentication, when clicked on `login` our application will redirect users to the Auth0 login page, so you don't have to create these on your own!
_Auth0 Login Page_
![Auth0 Login Page](https://dev-to-uploads.s3.amazonaws.com/i/9tevvv1dgle1mizvtx5v.jpg)

Once logged in, you will be able to see the winner's name and score.
![Authenticated Login](https://dev-to-uploads.s3.amazonaws.com/i/stubqzisngagmsbllu7d.png)

Well done! You have successfully integrated Auth0 in your Laravel 7 Application.

Source code for this application can be found on [Github](https://github.com/shahbaz17/Laravel-7-Authentication).