DEV Community

Cover image for Laravel 9 Auth Login and Registration with Username or Email
codeanddeploy
codeanddeploy

Posted on

Laravel 9 Auth Login and Registration with Username or Email

Originally posted @ https://codeanddeploy.com visit and download the sample code: https://codeanddeploy.com/blog/laravel/laravel-8-authentication-login-and-registration-with-username-or-email

In this post, I will share how to implement Laravel 8, 9 custom auth login and registration with username or email. We know that Laravel Framework is one of the best PHP Frameworks because of these advanced features and development tools that help make your development fast; that's why many PHP Developers use it and recommend it. Laravel additionally helps web developers to simplify their development process with clean and reusable code.

As I said above that I will share how to create a simple and clean authentication for your Laravel app with username or email. We know that authentication is one of the most important to implement before coding your application to control your users to access sensitive data.

laravel-8-authentication-login-and-registration-with-username-or-email

I will give you easy steps for you to understand clearly.

Step 1: Create Laravel App

I assume that you have already set up your composer on your system. Run the following coding to install the new Laravel app. However, you can skip this step if you have the Laravel app installed already.

composer create-project --prefer-dist laravel/laravel login-and-registration
Enter fullscreen mode Exit fullscreen mode

Next, navigate the login-and-registration folder with the following command.

cd login-and-registration
Enter fullscreen mode Exit fullscreen mode

Step 2: Setup Database Credentials

Next, create your database you can use the command to create a database or in PHPMyAdmin. Then once created navigate the .env file and update your database credentials.

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=your_db_name
DB_USERNAME=your_db_username
DB_PASSWORD=your_db_password

Enter fullscreen mode Exit fullscreen mode

The Laravel default comes with a User model and migration files. But before running the migrate command we need to update your user table migration which can be found here > {project_folder}\database\migrations\2014_10_12_000000_create_users_table.php and add the username field then update the name field to nullable so that in registration we require the email, username, and password. See the updated migration code below.

Schema::create('users', function (Blueprint $table) {
   $table->id();
   $table->string('name')->nullable();
   $table->string('email')->unique();
   $table->string('username')->unique();
   $table->timestamp('email_verified_at')->nullable();
   $table->string('password');
   $table->rememberToken();
   $table->timestamps();
});
Enter fullscreen mode Exit fullscreen mode

Once updated our migrations are now ready to migrate just run to your terminal the following command:

php artisan migrate
Enter fullscreen mode Exit fullscreen mode

Step 3: Setup Model

Next, we need to modify our App\Models\User.php model and add the username as fillable. See the updated code in the following:

/**
 * The attributes that are mass assignable.
 *
 * @var array
*/
protected $fillable = [
  'name',
  'email',
  'username',
  'password',
];
Enter fullscreen mode Exit fullscreen mode

Then next, we will add this method setPasswordAttribute so that for every user registered, the password will always be encrypted. This is called Laravel mutators to know more about it just visit their documentation here.

/**
 * Always encrypt the password when it is updated.
 *
  * @param $value
 * @return string
 */
public function setPasswordAttribute($value)
{
   $this->attributes['password'] = bcrypt($value);
}
Enter fullscreen mode Exit fullscreen mode

Don't worry to see the complete code of this User.php model just download the full source code of this tutorial below.

Step 4: Setup Registration Controller

To set up the registration controller just use your terminal and run the following command.

php artisan make:controller RegisterController
Enter fullscreen mode Exit fullscreen mode

Now, you already generated our RegistrerController which you can found it here > App\Http\Controllers\RegisterController.php now open it and see the following code below:

<?php

namespace App\Http\Controllers;

use App\Models\User;
use Illuminate\Http\Request;
use App\Http\Requests\RegisterRequest;

class RegisterController extends Controller
{
    /**
     * Display register page.
     * 
     * @return \Illuminate\Http\Response
     */
    public function show()
    {
        return view('auth.register');
    }

    /**
     * Handle account registration request
     * 
     * @param RegisterRequest $request
     * 
     * @return \Illuminate\Http\Response
     */
    public function register(RegisterRequest $request) 
    {
        $user = User::create($request->validated());

        auth()->login($user);

        return redirect('/')->with('success', "Account successfully registered.");
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 5: Setup Registration Request

We need to separate our request validation for our registration process. So that our code is clean in our controller and not bloated. So we will create our RegisterRequest just follow the following command below:

php artisan make:request RegisterRequest
Enter fullscreen mode Exit fullscreen mode

Now you have already created the RegisterRequest which you can find it here > App\Http\Requests\RegisterRequest.php then next we will add our validation rules. Just see the following code below:

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class RegisterRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'email' => 'required|email:rfc,dns|unique:users,email',
            'username' => 'required|unique:users,username',
            'password' => 'required|min:8',
            'password_confirmation' => 'required|same:password'
        ];
    }
}
Enter fullscreen mode Exit fullscreen mode

Now you have a registration validation already.

Step 6: Setup Login Controller

To set up the login controller just use your terminal and run the following command.

php artisan make:controller LoginController
Enter fullscreen mode Exit fullscreen mode

Now, you already generated our LoginController which you can found it here > App\Http\Controllers\LoginController.php now open it and see the following code below:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Http\Requests\LoginRequest;
use Illuminate\Support\Facades\Auth;

class LoginController extends Controller
{
    /**
     * Display login page.
     * 
     * @return Renderable
     */
    public function show()
    {
        return view('auth.login');
    }

    /**
     * Handle account login request
     * 
     * @param LoginRequest $request
     * 
     * @return \Illuminate\Http\Response
     */
    public function login(LoginRequest $request)
    {
        $credentials = $request->getCredentials();

        if(!Auth::validate($credentials)):
            return redirect()->to('login')
                ->withErrors(trans('auth.failed'));
        endif;

        $user = Auth::getProvider()->retrieveByCredentials($credentials);

        Auth::login($user);

        return $this->authenticated($request, $user);
    }

    /**
     * Handle response after user authenticated
     * 
     * @param Request $request
     * @param Auth $user
     * 
     * @return \Illuminate\Http\Response
     */
    protected function authenticated(Request $request, $user) 
    {
        return redirect()->intended();
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 7: Setup Login Request

Next, we will create our LoginRequest just follow the following command below:

php artisan make:request LoginRequest
Enter fullscreen mode Exit fullscreen mode

Now you have already created the LoginRequest which you can find it here > App\Http\Requests\LoginRequest.php then next we will add our validation rules. Just see the following code below:

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Contracts\Validation\Factory as ValidationFactory;

class LoginRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'username' => 'required',
            'password' => 'required'
        ];
    }

    /**
     * Get the needed authorization credentials from the request.
     *
     * @return array
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
     */
    public function getCredentials()
    {
        // The form field for providing username or password
        // have name of "username", however, in order to support
        // logging users in with both (username and email)
        // we have to check if user has entered one or another
        $username = $this->get('username');

        if ($this->isEmail($username)) {
            return [
                'email' => $username,
                'password' => $this->get('password')
            ];
        }

        return $this->only('username', 'password');
    }

    /**
     * Validate if provided parameter is valid email.
     *
     * @param $param
     * @return bool
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
     */
    private function isEmail($param)
    {
        $factory = $this->container->make(ValidationFactory::class);

        return ! $factory->make(
            ['username' => $param],
            ['username' => 'email']
        )->fails();
    }
}
Enter fullscreen mode Exit fullscreen mode

As you can see above our LoginRequest.php we have our additional method called getCredentials() this function will support the username/email login as you can see we have username checking above if email or not.

Step 8: Setup Logout Controller

To set up the logout controller just use your terminal and run the following command.

php artisan make:controller LogoutController
Enter fullscreen mode Exit fullscreen mode

Now, you already generated our LogoutController which you can found it here > App\Http\Controllers\LogoutController.php now open it and see the following code below:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Session;

class LogoutController extends Controller
{
    /**
     * Log out account user.
     *
     * @return \Illuminate\Routing\Redirector
     */
    public function perform()
    {
        Session::flush();

        Auth::logout();

        return redirect('login');
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 9: Setup Home Controller

To set up the logout controller just use your terminal and run the following command.

php artisan make:controller HomeController
Enter fullscreen mode Exit fullscreen mode

Now, you already generated our HomeController which you can found it here > App\Http\Controllers\HomeController.php now open it and see the following code below:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class HomeController extends Controller
{
    public function index() 
    {
        return view('home.index');
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 10: Setup Routes

Next, we will set up our routes which we can find here routes/web.php since we have already set up our controllers and validators.

<?php

use Illuminate\Support\Facades\Route;

/*
|--------------------------------------------------------------------------
| 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::group(['namespace' => 'App\Http\Controllers'], function()
{   
    /**
     * Home Routes
     */
    Route::get('/', 'HomeController@index')->name('home.index');

    Route::group(['middleware' => ['guest']], function() {
        /**
         * Register Routes
         */
        Route::get('/register', 'RegisterController@show')->name('register.show');
        Route::post('/register', 'RegisterController@register')->name('register.perform');

        /**
         * Login Routes
         */
        Route::get('/login', 'LoginController@show')->name('login.show');
        Route::post('/login', 'LoginController@login')->name('login.perform');

    });

    Route::group(['middleware' => ['auth']], function() {
        /**
         * Logout Routes
         */
        Route::get('/logout', 'LogoutController@perform')->name('logout.perform');
    });
});
Enter fullscreen mode Exit fullscreen mode

As you can see above in this line "Route::group(['middleware' => ['auth']], function() {" we protected the logout route that can be access only if user authenticated. If you have other routes that need to protect just add on this route group.

Step 11: Setup Our View

Next, we will set up our views using Bootstrap with a simple theme layout. To know more about bootstrap documentation just visit here.

You need to create a layouts folder inside resources/views then create a file resources/views/layouts/auth-master.blade.php see the following code below:

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="description" content="">
    <meta name="author" content="Mark Otto, Jacob Thornton, and Bootstrap contributors">
    <meta name="generator" content="Hugo 0.87.0">
    <title>Signin Template · Bootstrap v5.1</title>

    <!-- Bootstrap core CSS -->
    <link href="{!! url('assets/bootstrap/css/bootstrap.min.css') !!}" rel="stylesheet">
    <link href="{!! url('assets/css/signin.css') !!}" rel="stylesheet">

    <style>
      .bd-placeholder-img {
        font-size: 1.125rem;
        text-anchor: middle;
        -webkit-user-select: none;
        -moz-user-select: none;
        user-select: none;
      }

      @media (min-width: 768px) {
        .bd-placeholder-img-lg {
          font-size: 3.5rem;
        }
      }
    </style>


    <!-- Custom styles for this template -->
    <link href="signin.css" rel="stylesheet">
</head>
<body class="text-center">

    <main class="form-signin">

        @yield('content')

    </main>


</body>
</html>
Enter fullscreen mode Exit fullscreen mode

Next, create a file resources/views/layouts/app-master.blade.php see the following code below:

<!doctype html>
<html lang="en">
    <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="description" content="">
    <meta name="author" content="Mark Otto, Jacob Thornton, and Bootstrap contributors">
    <meta name="generator" content="Hugo 0.87.0">
    <title>Fixed top navbar example · Bootstrap v5.1</title>

    <!-- Bootstrap core CSS -->
    <link href="{!! url('assets/bootstrap/css/bootstrap.min.css') !!}" rel="stylesheet">

    <style>
      .bd-placeholder-img {
        font-size: 1.125rem;
        text-anchor: middle;
        -webkit-user-select: none;
        -moz-user-select: none;
        user-select: none;
      }

      @media (min-width: 768px) {
        .bd-placeholder-img-lg {
          font-size: 3.5rem;
        }
      }
    </style>


    <!-- Custom styles for this template -->
    <link href="{!! url('assets/css/app.css') !!}" rel="stylesheet">
</head>
<body>

    @include('layouts.partials.navbar')

    <main class="container">
        @yield('content')
    </main>

    <script src="{!! url('assets/bootstrap/js/bootstrap.bundle.min.js') !!}"></script>

  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

Next, create a new folder inside resources/views/layouts called partials folder then create a file resources/views/layouts/partials/navbar.blade.php see the following code below:

<header class="p-3 bg-dark text-white">
  <div class="container">
    <div class="d-flex flex-wrap align-items-center justify-content-center justify-content-lg-start">
      <a href="/" class="d-flex align-items-center mb-2 mb-lg-0 text-white text-decoration-none">
        <svg class="bi me-2" width="40" height="32" role="img" aria-label="Bootstrap"><use xlink:href="#bootstrap"/></svg>
      </a>

      <ul class="nav col-12 col-lg-auto me-lg-auto mb-2 justify-content-center mb-md-0">
        <li><a href="#" class="nav-link px-2 text-secondary">Home</a></li>
        <li><a href="#" class="nav-link px-2 text-white">Features</a></li>
        <li><a href="#" class="nav-link px-2 text-white">Pricing</a></li>
        <li><a href="#" class="nav-link px-2 text-white">FAQs</a></li>
        <li><a href="#" class="nav-link px-2 text-white">About</a></li>
      </ul>

      <form class="col-12 col-lg-auto mb-3 mb-lg-0 me-lg-3">
        <input type="search" class="form-control form-control-dark" placeholder="Search..." aria-label="Search">
      </form>

      @auth
        {{auth()->user()->name}}
        <div class="text-end">
          <a href="{{ route('logout.perform') }}" class="btn btn-outline-light me-2">Logout</a>
        </div>
      @endauth

      @guest
        <div class="text-end">
          <a href="{{ route('login.perform') }}" class="btn btn-outline-light me-2">Login</a>
          <a href="{{ route('register.perform') }}" class="btn btn-warning">Sign-up</a>
        </div>
      @endguest
    </div>
  </div>
</header>
Enter fullscreen mode Exit fullscreen mode

Then next, create a file resources/views/layouts/partials/messages.blade.php see the following code below:

@if(isset ($errors) && count($errors) > 0)
    <div class="alert alert-warning" role="alert">
        <ul class="list-unstyled mb-0">
            @foreach($errors->all() as $error)
                <li>{{ $error }}</li>
            @endforeach
        </ul>
    </div>
@endif

@if(Session::get('success', false))
    <?php $data = Session::get('success'); ?>
    @if (is_array($data))
        @foreach ($data as $msg)
            <div class="alert alert-warning" role="alert">
                <i class="fa fa-check"></i>
                {{ $msg }}
            </div>
        @endforeach
    @else
        <div class="alert alert-warning" role="alert">
            <i class="fa fa-check"></i>
            {{ $data }}
        </div>
    @endif
@endif
Enter fullscreen mode Exit fullscreen mode

Then next, create our auth folder inside resources/views then create a file resources/views/auth/register.blade.php see the following code below:

@extends('layouts.auth-master')

@section('content')
    <form method="post" action="{{ route('register.perform') }}">

        <input type="hidden" name="_token" value="{{ csrf_token() }}" />
        <img class="mb-4" src="{!! url('images/bootstrap-logo.svg') !!}" alt="" width="72" height="57">

        <h1 class="h3 mb-3 fw-normal">Register</h1>

        <div class="form-group form-floating mb-3">
            <input type="email" class="form-control" name="email" value="{{ old('email') }}" placeholder="name@example.com" required="required" autofocus>
            <label for="floatingEmail">Email address</label>
            @if ($errors->has('email'))
                <span class="text-danger text-left">{{ $errors->first('email') }}</span>
            @endif
        </div>

        <div class="form-group form-floating mb-3">
            <input type="text" class="form-control" name="username" value="{{ old('username') }}" placeholder="Username" required="required" autofocus>
            <label for="floatingName">Username</label>
            @if ($errors->has('username'))
                <span class="text-danger text-left">{{ $errors->first('username') }}</span>
            @endif
        </div>

        <div class="form-group form-floating mb-3">
            <input type="password" class="form-control" name="password" value="{{ old('password') }}" placeholder="Password" required="required">
            <label for="floatingPassword">Password</label>
            @if ($errors->has('password'))
                <span class="text-danger text-left">{{ $errors->first('password') }}</span>
            @endif
        </div>

        <div class="form-group form-floating mb-3">
            <input type="password" class="form-control" name="password_confirmation" value="{{ old('password_confirmation') }}" placeholder="Confirm Password" required="required">
            <label for="floatingConfirmPassword">Confirm Password</label>
            @if ($errors->has('password_confirmation'))
                <span class="text-danger text-left">{{ $errors->first('password_confirmation') }}</span>
            @endif
        </div>

        <button class="w-100 btn btn-lg btn-primary" type="submit">Register</button>

        @include('auth.partials.copy')
    </form>
@endsection
Enter fullscreen mode Exit fullscreen mode

Then create a partials folder inside auth folder. Then create a file resources/views/auth/partials/copy.blade.php see the following code below:

<p class="mt-5 mb-3 text-muted">&copy; {{date('Y')}}</p>
Enter fullscreen mode Exit fullscreen mode

Then last create a home folder inside the resources/views folder then create a file resources/views/home/index.blade.php see the following code below:

@extends('layouts.app-master')

@section('content')
    <div class="bg-light p-5 rounded">
        @auth
        <h1>Dashboard</h1>
        <p class="lead">Only authenticated users can access this section.</p>
        <a class="btn btn-lg btn-primary" href="https://codeanddeploy.com" role="button">View more tutorials here &raquo;</a>
        @endauth

        @guest
        <h1>Homepage</h1>
        <p class="lead">Your viewing the home page. Please login to view the restricted data.</p>
        @endguest
    </div>
@endsection
Enter fullscreen mode Exit fullscreen mode

Now our views are already set up. Next, we need to download bootstrap and save it inside the public/assets directory.

This is the bootstrap files example in this tutorial:

public/assets/bootstrap/css/bootstrap.min.css

public/assets/bootstrap/js/bootstrap.bundle.min.js

Or download the source code of this tutorial below.

Now our Laravel authentication with username or email login is ready but we have another small customization the redirect default after login. Which we can found in App\Providers\RouteServiceProvider.php then change the original code below:

/**
* The path to the "home" route for your application.
*
* This is used by Laravel authentication to redirect users after login.

* @var string
*/
public const HOME = '/home';
Enter fullscreen mode Exit fullscreen mode

to this code.

/**
* The path to the "home" route for your application.
*
* This is used by Laravel authentication to redirect users after login.
*
* @var string
*/
public const HOME = '/';
Enter fullscreen mode Exit fullscreen mode

But take note it's up to you to change it. I just give you an idea of how to modify it that is suitable to your need. If you need to redirect after login to /dashboard or /admin then it's up to you to change it.

Step 12: Run The Development Server

Finally, we have already done the process of our Laravel authentication. Let's run a command to your terminal to run your server and test if our code is working.

php artisan serve
Enter fullscreen mode Exit fullscreen mode

And add the following URL to your web browser.\

http://127.0.0.1:8000/
Enter fullscreen mode Exit fullscreen mode

You will see the homepage if not yet authenticated as shown below:

laravel-8-authentication-login-and-registration-with-username-or-email

laravel-8-authentication-login-and-registration-with-username-or-email

As you can see now you already see the Logout menu above.

Now you have a custom Laravel registration and login with username/email that can apply to your app. I hope this simple tutorial may help you.

NOTE: Don't forget to import the classes uses in a specific class or controller when copying my code above.

I hope this tutorial can help you. Kindly visit here https://codeanddeploy.com/blog/laravel/laravel-8-authentication-login-and-registration-with-username-or-email if you want to download this code.

Happy coding :)

Discussion (0)