In our previous article, we installed and setup Laravel. In this article, we will implement user accounts so users can sign up and sign in to use our app. Let's complete our Passport setup.

First, create a folder in apps called Models and move the App\User model there so it is now App\Models\User. Change references to App\User to App\Models\User in database/factories/UserFactory.php, config/services.php, config/auth.php and app/Http/Controllers/Auth/RegisterController.php.

Add the Laravel\Passport\HasApiTokens trait to the App\Models\User class.

It's better to use UUIDs instead of integer ids in event sourcing to eliminate the risk of having duplicate keys. So, we'll be using UUIDs on our models.

Your App\Models\User class should look like this:

<?php

namespace App\Models;

use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Laravel\Passport\HasApiTokens;

class User extends Authenticatable {
  use Traits\UsesUuid, HasApiTokens, Notifiable;

  protected $guarded = [];

  public $incrementing = false;

  /**
   * The attributes that should be hidden for arrays.
   *
   * @var array
   */
  protected $hidden = [
    'password', 'remember_token',
  ];
}

Here's the trait app/Models/Traits/UsesUuid.php and my user migration:

<?php

namespace App\Models\Traits;

use Ramsey\Uuid\Uuid;

trait UsesUuid {
  protected static function bootUsesUuid() {
    static::creating(function ($model) {
      if ((! $model->incrementing) && empty($model->{$model->getKeyName()})) {
        $model->{$model->getKeyName()} = (string) Uuid::uuid4();
      }
    });
  }

  public function getKeyType() {
    return 'string';
  }
}
<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateUsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->uuid('id')->primary();
            $table->string('name');
            $table->string('email')->unique();
            $table->string('password');
            $table->rememberToken();
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('users');
    }
}

Modify app/Providers/AuthServiceProvider.php to look like this:

<?php

namespace App\Providers;

use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Laravel\Passport\Passport;

class AuthServiceProvider extends ServiceProvider
{
    /**
     * The policy mappings for the application.
     *
     * @var array
     */
    protected $policies = [
        // 'App\Model' => 'App\Policies\ModelPolicy',
    ];

    /**
     * Register any authentication / authorization services.
     *
     * @return void
     */
    public function boot()
    {
        $this->registerPolicies();

        Passport::routes();
    }
}

Set the api driver to passport in config/auth.php.

Add \Laravel\Passport\Http\Middleware\CreateFreshApiToken::class to app/Http/Kernel.php's $middlewareGroups.

Run php artisan make:auth to publish the built-in authentication views. Do not replace layouts/app.blade.php when asked.

Change the $redirectTo value to /contacts in app/Http/Controllers/Auth/RegisterController.php and app/Http/Controllers/Auth/LoginController.php.

Alter resources/views/welcome.blade.php to this:

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

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

    <!-- Fonts -->
    <link href="https://fonts.googleapis.com/css?family=Nunito:200,600" rel="stylesheet">

    <!-- Styles -->
    <style>
      html, body {
        background-color: #fff;
        color: #636b6f;
        font-family: 'Nunito', sans-serif;
        font-weight: 200;
        height: 100vh;
        margin: 0;
      }

      .full-height {
        height: 100vh;
      }

      .flex-center {
        align-items: center;
        display: flex;
        justify-content: center;
      }

      .position-ref {
        position: relative;
      }

      .top-right {
        position: absolute;
        right: 10px;
        top: 18px;
      }

      .content {
        text-align: center;
      }

      .title {
        font-size: 84px;
      }

      .links > a {
        color: #636b6f;
        padding: 0 25px;
        font-size: 13px;
        font-weight: 600;
        letter-spacing: .1rem;
        text-decoration: none;
        text-transform: uppercase;
      }

      .m-b-md {
        margin-bottom: 30px;
      }
    </style>
  </head>
  <body>
    <div class="flex-center position-ref full-height">
      @if (Route::has('login'))
        <div class="top-right links">
          @auth
            <a href="{{ url('/contacts') }}">Contacts</a>
          @else
            <a href="{{ route('login') }}">Login</a>

            @if (Route::has('register'))
              <a href="{{ route('register') }}">Register</a>
            @endif
          @endauth
        </div>
      @endif

      <div class="content">
        <div class="title m-b-md">
          {{ config('app.name', 'Address Book') }}
        </div>
      </div>
    </div>
  </body>
</html>

Replace the contents of routes/web.php with:

<?php

Auth::routes();

Route::get('/', 'HomeController@welcome')->name('welcome');

Route::group(['middleware' => ['auth']], function() {
  Route::get('/logout', 'Auth\LoginController@logout');
  Route::get('/contacts', 'HomeController@contacts')->name('contacts');
});

Replace the contents of app/Http/Controllers/HomeController.php with:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class HomeController extends Controller {
  public function welcome() {
    return view('welcome');
  }

  public function contacts() {
    return view('contacts', ['contacts' => []]);
  }
}

Create a new view resources/views/contacts.blade.php with the following template:

@extends('layouts.app')

@section('content')
<div class="container">
  <div class="row justify-content-center">
    <div class="col-sm-12">
      <!--  -->
    </div>
  </div>
</div>
@endsection

If you haven't already, run migrations with php artisan migrate:fresh and start up the app by running php artisan serve in one command window and npm run watch in another.

Go ahead and create an account.

Next, we'll be working on contacts.

You can explore the changes here.