Click to share! ⬇️

How To Create User Registration in Laravel

In this tutorial, we are going to hand build a user registration system in Laravel. To be fair, we could actually make use of the php artisan make:auth command to scaffold basic login and registration views and routes automatically for us. This works great, but in the spirit of learning, we should know how to do this on our own. By building an example of user registration and session management from scratch, we will gain a much better idea of how to maintain and adjust these features as we need to moving forward. Let’s go ahead and tackle user registration and session management from scratch right now.


Set up Registration and Sessions Routes

Starting at the routes file makes sense. This gives us a way to map out what we want to implement. It’s almost like a way of using pseudo code to look into the future to see what we will need to make something work.


routes/web.php

<?php

Route::get('/games', 'GamesController@index');

Route::get('/games/create', 'GamesController@create');

Route::get('/games/{game}', 'GamesController@show');

Route::post('/games', 'GamesController@store');

Route::post('/games/{game}/reviews', 'ReviewsController@store');

Route::get('/register', 'RegistrationController@create');
Route::post('register', 'RegistrationController@store');

Route::get('/login', 'SessionsController@create');
Route::post('/login', 'SessionsController@store');
Route::get('/logout', 'SessionsController@destroy');

Here, we’ve broken the task of registering a user vs session related actions (sign in / sign out) into their own controllers. The RegistrationController will handle offering a form to register a new user, as well as a way to store a new user in the database once a form has been filled out properly. The SessionsController is dedicated to handling offering a form to sign in an existing user, signing them in if they fill out their credentials correctly, and also logging them out when they like. You might be wondering why we use two controllers when it seems it could all be handled in a dedicated AuthController of some type. The truth is, that yes, you could easily do this in one controller. The reason here for two, is so that we can more easily follow the RESTful method structure and be able to default to any of the RESTful methods we might find for a resource. In other words, index(), create(), store(), show(), edit(), update(), or destroy().

With regard to the routes we have laid out so far, we know that the create() method will typically display a form to the user. From there they can fill it out and submit it. When they submit it, they should send a POST request to a store() method. This method will either create a new user in the case of RegistrationController, or sign in an existing user in the case of SessionsController. Lastly, if an authenticated user visits the /logout route, the destroy() method on the SessionsController will run and log them out of the session. Makes perfect sense.


Build The Registration Controller

Now that we have our routes taken care of, it’s time to build out the controllers. We can start with the RegistrationController.
make a registration controller

We’ll fist focus on adding the create() method which should display a form to the user so he or she can fill out their information to sign up.


app/Http/Controllers/RegistrationController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class RegistrationController extends Controller
{
    public function create()
    {
        return view('registration.create');
    }
}

Create a Registration Form for the RegistrationController@create() method

We don’t yet have a registration form, so let’s create a folder in our resources directory named registration, and add a create.blade.php view file. Now recall that the value of the name attribute on our input tags are going to be how we fetch the data submitted in the form on the back end. What we do here is to use the field names of our current users table in our database. These were created by default when we first ran php artisan migrate. Note that we have the users table, and we can see the fields of the table, but no users exist yet.
no users yet


resources/views/registration/create.blade.php

@extends('layouts.master')

@section('content')

    <h2>Register</h2>
    <form method="POST" action="/register">
        {{ csrf_field() }}
        <div class="form-group">
            <label for="name">Name:</label>
            <input type="text" class="form-control" id="name" name="name">
        </div>

        <div class="form-group">
            <label for="email">Email:</label>
            <input type="email" class="form-control" id="email" name="email">
        </div>

        <div class="form-group">
            <label for="password">Password:</label>
            <input type="password" class="form-control" id="password" name="password">
        </div>

        <div class="form-group">
            <button style="cursor:pointer" type="submit" class="btn btn-primary">Submit</button>
        </div>
        @include('partials.formerrors')
    </form>

@endsection

If we visit the /register route, it looks like we do now have our form. Great!
new user registration form laravel


Set up the RegistrationController@store() method to handle registration form submission

We have a form in place to register a new user, but we need a method in our RegisterController to handle this request. When the form is submitted, it will send a POST request to /register, which in turn routes to the store() method. This method is going to need to do a few things.

  • Validate the form submission
  • Create and save a user to the database
  • Redirect the user to the games route

Let’s set that up right here.


app/Http/Controllers/RegistrationController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\User;

class RegistrationController extends Controller
{
    public function create()
    {
        return view('registration.create');
    }
    
    public function store()
    {
        $this->validate(request(), [
            'name' => 'required',
            'email' => 'required|email',
            'password' => 'required'
        ]);
        
        $user = User::create(request(['name', 'email', 'password']));
        
        auth()->login($user);
        
        return redirect()->to('/games');
    }
}

Add password hashing with a mutator on the User Model

Before we test this out, we need to discuss a little bit about security with regard to passwords being stored in a database. The store() method above will work, but it is going to store the password in plain text in the database. Passwords should always be stored as a hash or unique token by running the string through a function like bcrypt(). This is a security hole that we need to fix. We can fix this by adding a mutator to the User model. Let’s see how to do that.


app/User.php

<?php

namespace App;

use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    use Notifiable;
    
    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name', 'email', 'password',
    ];
    
    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password', 'remember_token',
    ];
    
    /**
     * Add a mutator to ensure hashed passwords
     */
    public function setPasswordAttribute($password)
    {
        $this->attributes['password'] = bcrypt($password);
    }
}

We can now test out the new user form to make sure it is working. Let’s register Mario to our games database.
register new user mario to the database

If we look at the user in our database, we can see that Mario is in there! Note that his password is properly hashed as well, no clear text. This tells us that our mutator on the User model worked perfectly.
sucessful user registration with password hashing


Display the user’s name in the Navbar

Note that in the store() method, we captured an instance of the new user when we used $user = User::create(request([‘name’, ’email’, ‘password’])); This put an instance of that new user into the $user variable. The very next thing we did was to log that user in with auth()->login($user); What did this actually do? Well, it established a new session for that user with the site. If a user has an active session, it might be nice to display their user name in the Navbar for a bit of customization. We can update our navbar partial like so to handle that.


resources/views/partials/navbar.blade.php

In this snippet we use auth()->check() to see if the user is logged in. If this is true, then the <li> tag is rendered and the user name is populated via auth()->user()->name. If this is false, the <li> is not rendered at all. Perfect.

<nav class="navbar navbar-toggleable-md navbar-light bg-faded">
    <button class="navbar-toggler navbar-toggler-right" 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>
    <a class="navbar-brand" href="#">We Like Games</a>

    <div class="collapse navbar-collapse" id="navbarSupportedContent">
        <ul class="navbar-nav mr-auto">
            <li class="nav-item">
                <a class="nav-link" href="/games">List Games</a>
            </li>
            @if( auth()->check() )
                <li class="nav-item">
                    <a class="nav-link" href="#">{{ auth()->user()->name }}</a>
                </li>
            @endif
        </ul>
    </div>
</nav>

mario is logged in


Build The Session Controller

We now need a way to log existing users in and out of the application. We already have our routes in place to handle this, we now need to build the actual controller and associated methods to handle this for us. We can do that now.
laravel generate sesson controller


app/Http/Controllers/SessionsController.php

In our routes file, we already determined that there will be three methods on the SessionsController. Those will be create() to offer a login form, store() to log an existing user in, and destroy() to log a user out of the application. We can build those methods now.

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class SessionsController extends Controller
{
    public function create()
    {
        return view('sessions.create');
    }
    
    public function store()
    {
        if (auth()->attempt(request(['email', 'password'])) == false) {
            return back()->withErrors([
                'message' => 'The email or password is incorrect, please try again'
            ]);
        }
        
        return redirect()->to('/games');
    }
    
    public function destroy()
    {
        auth()->logout();
        
        return redirect()->to('/games');
    }
}

Create a Log In Form for the SessionsController@create() method

Just like the create() method in our RegistrationController offers a form to the user to register to the site, so too will the create() method in our SessionsController offer the user a form to Log In to the site. This form is a little more simple as it only needs to include fields for an email and password. We’ll also include the partial we had created earlier for displaying errors.


@extends('layouts.master')

@section('content')

    <h2>Log In</h2>
    
    <form method="POST" action="/login">
        {{ csrf_field() }}
        <div class="form-group">
            <label for="email">Email:</label>
            <input type="email" class="form-control" id="email" name="email">
        </div>

        <div class="form-group">
            <label for="password">Password:</label>
            <input type="password" class="form-control" id="password" name="password">
        </div>

        <div class="form-group">
            <button style="cursor:pointer" type="submit" class="btn btn-primary">Login</button>
        </div>
        @include('partials.formerrors')
    </form>

@endsection

Looking Good!
create method renders a log in form

In the store() method of the SessionsController we can see we make use of the auth()->attempt(request([’email’, ‘password’]) method which returns false if the user fails to log in, or true if the user logs in successfully. Knowing this, we can place this call in an if statement. If the auth()->attempt() method is false, we return back to the form with any errors. We use the back() and withErrors() functions to do this. Here we manually set the message to: The email or password is incorrect, please try again. If the If the auth()->attempt() is true however, that means the user logged in successfully and we can now redirect them to the /games route to view all games. We have a Mario user in the system, but not a Luigi. Let’s try to log in as Luigi and see what happens.
luigi can not log in bad credentials
The log in form is working good in the case of providing bad credentials. We are redirected back to the form, and the errors show up nicely below the form. If we provide the correct credentials for Mario, who is already in the database, we log in just fine.


Update Navigation to include Log In, Register, and Log Out links

The last method in our SessionsController is the destroy() method, and all it does is call auth()->logout(); and then redirect the user to the /games route to view all games. In order to make use of these routes, we should really add some navigation links to our layout. We will need to account for what links to show based on whether a user is logged in or not. In our navigation right now, we have a link to /games to view all games. We want to show this for both logged in or logged out users. If a user is not yet logged in, we should give them a link to both /login and /register. This way they can choose to log in if they are an existing user, or create a new account by registering with the site if they like. If the user is logged in, we will want to display their name, as well as give them a link to /logout so they can log out if they like. Here is how we will do that in our navigation area.


resources/views/partials/navbar.blade.php

<nav class="navbar navbar-toggleable-md navbar-light bg-faded">
    <button class="navbar-toggler navbar-toggler-right" 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>
    <a class="navbar-brand" href="#">We Like Games</a>

    <div class="collapse navbar-collapse" id="navbarSupportedContent">
        <ul class="navbar-nav ml-auto">
            <li class="nav-item">
                <a class="nav-link" href="/games">List Games</a>
            </li>
            @if( auth()->check() )
                <li class="nav-item">
                    <a class="nav-link font-weight-bold" href="#">Hi {{ auth()->user()->name }}</a>
                </li>
                <li class="nav-item">
                    <a class="nav-link" href="/logout">Log Out</a>
                </li>
            @else
                <li class="nav-item">
                    <a class="nav-link" href="/login">Log In</a>
                </li>
                <li class="nav-item">
                    <a class="nav-link" href="/register">Register</a>
                </li>
            @endif
        </ul>
    </div>
</nav>

Register a new user

Let’s try to register a new user named Luigi now.
luigi registers for the site
Looks like our work is paying off. We visit the /register route via the new link we created and we get the Registration form we expect. We then fill out some information, submit, and voila, we have a new user created which immediately gets logged in. We can also see that the navbar updates as we would expect based on if we are logged in or not. Finally, we visit the /logout route via the Log Out link we provided, and we log right out. Awesome!

Let’s do a final check to make sure Mario, our first user, can still log in and out properly.
mario logs in and logs out
We can see that both users that we have registered to the site are able to log in and out now with our user registration system. Excellent work!


Add Password Confirmation To Registration Form

The last thing we’ll do for this tutorial is to add a password confirmation field to our registration form. You are likely familiar with this. It is when you need to type your password two times to ensure that you did not make a typo when choosing a password. First we can update the form.


resources/views/registration/create.blade.php

@extends('layouts.master')

@section('content')

    <h2>Register</h2>
    <form method="POST" action="/register">
        {{ csrf_field() }}
        <div class="form-group">
            <label for="name">Name:</label>
            <input type="text" class="form-control" id="name" name="name">
        </div>

        <div class="form-group">
            <label for="email">Email:</label>
            <input type="email" class="form-control" id="email" name="email">
        </div>

        <div class="form-group">
            <label for="password">Password:</label>
            <input type="password" class="form-control" id="password" name="password">
        </div>

        <div class="form-group">
            <label for="password_confirmation">Password Confirmation:</label>
            <input type="password" class="form-control" id="password_confirmation"
                   name="password_confirmation">
        </div>

        <div class="form-group">
            <button style="cursor:pointer" type="submit" class="btn btn-primary">Submit</button>
        </div>
        @include('partials.formerrors')
    </form>

@endsection

add password confirmation to register form

We now need to update the validation rules in the RegistrationController@store() method. Very easy to do.

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\User;

class RegistrationController extends Controller
{
    public function create()
    {
        return view('registration.create');
    }
    
    public function store()
    {
        $this->validate(request(), [
            'name' => 'required',
            'email' => 'required|email',
            'password' => 'required|confirmed'
        ]);
        
        $user = User::create(request(['name', 'email', 'password']));
        
        auth()->login($user);
        
        return redirect()->to('/games');
    }
}

We can try to register a new user, and intentionally mismatch the passwords, and the validation works perfect for us.
the password confirmation does not match


How To Create User Registration in Laravel Summary

We took a RESTful approach to handling user registration and session handling in this tutorial, and made use of the well known methods of create(), store() and destroy() to do the work for us. We learned that a create() method typically is used to display a form to a user. We are seeking input data in this case. The store() method is used to process the data we collected with a form rendered via the create() method. Lastly the destroy() method is used to delete a resource. In this case, that was the act of removing a user session. By breaking the registration and session handling into two controllers of RegistrationController and SessionController, it made it easy to adhere to those RESTful methods, which is nice. In summary:

  • Route::get(‘/register’, ‘RegistrationController@create’); Display a form to a visitor so they can register for a new account with the site.
  • Route::post(‘/register’, ‘RegistrationController@store’); Accepts request data from the registration form submission, validates data, stores new user in the database.
  • Route::get(‘/login’, ‘SessionsController@create’); Display a form for an existing user to log in to the site and establish a new session.
  • Route::post(‘/login’, ‘SessionsController@store’); Accepts request data from log in (or session) form submission, authorizes credentials, logs user into the site.
  • Route::get(‘/logout’, ‘SessionsController@destroy’); Destroys an existing session and logs the user out of the site.

Now go check out how to set up Node.js user registration!

Click to share! ⬇️