Laravel is so powerful for such a young framework. I am constantly surprised at how functionality is built in and so well thought out. One example of this incredible design, is Laravel’s ability to not only spin up authentication with one command in the terminal, but also to expand that authentication with so many awesome features like user roles, permissions, multi-authentication, social login, and more.
What is Multi-Authentication?
When i use the term multi-authentication, I want to clarify what I am talking about. I am talking about authenticating against multiple user models. It is important to note that this is different user models, and not just user roles. User roles can be achieved in a much simpler and less invasive process than what I am going to teach here. Today we are learning about authenticating against 2 (or more) different User models.
An example of this would be an ecommerce application. You have customers that have a login to your system and you store their information in the database. You process their orders, store their order history, payment tokens (because storing payment info directly would be sketchy…), manage their wishlists, and more. Customers need to be able to login to store and manage this data and will have profile pages. On the other hand, you also have employees of the company that need to log into another type of backend which allows them to manage products, refund orders, update shipping information, add coupons, and more. These are two entirely exclusive types of users. User roles would not work very elegantly in this situation because there are entirely different backends views/controllers, routes, and middleware between the two user types. In addition it wouldn’t make sense to share the same database table for these two different types of users because they are so different. Employee users will have database relationships with content that customers need no part in, and vice versa. This is a scenario when managing two different user models makes sense, Employees and Customers.
Let’s briefly look at the flip side of this, a case when Multi-authentication would be a BAD idea. Let’s explore the setup of a content management system or a blog. In this scenario you definitely want different types of users, but not necessarily different user models. We will have Authors that log into a backend so they can edit their own posts, Editors that log into the same backend to edit their posts, and also edit other Author’s posts. Finally we have Admins who have access to their own posts, everyone else’s posts, and global settings. In this example User Roles and Permissions is a better management paradigm than Multi-Authentication because these users can all be managed in the same model. Admins might have access to some more pages than other users, but they are still the same type of user as an Author or Editor, only they have more privileges. So we can store them in the same user model, maintain one backend and just restrict certain features or privileges to certain User Roles.
I point out this distinction because many loyal followers and YouTube Subscribers have been following this tutorial in the second example given above, when User Roles makes more sense. Before following this tutorial, take a moment to conceptualize your app and understand if this is the right path to take. Do you really need two user models, or are you looking for one model with multiple user permissions? I would say that 8/10 applications are better suited for User Roles than Multi-Authentication.
So you have considered your app and know that Multi-Authentication is the right type of Authentication for you? Great, carry on and let’s build!
Multi-Authentication in Laravel 5.4 Series
This is a long series covering this in 5 easy steps. Videos are available on YouTube covering the content in detail. The videos might get long as they cover lots of details and concepts, teaching you how this system works. The written tutorials are great for those looking for an easy step-by-step guide on doing this.
Part 1: Setting Up Multiple User Models
Part 2:
Part 3:
Part 4:
Part 5:
Let’s Get Started
To begin the process of setting up Multi-Authentication in Laravel, we will run the default authentication script. Hopefully you are already familiar with this and what it does. The reason we start from this is that it will give us the baseline to work with. It will set up on of our users right out of the box, and then we will use what it generates to work on our second user type.
In the terminal run the authentication scaffolding:
php artisan make:auth
Now we have a lot of new files in our application that we can start working with. The authentication will be set up around our default User.php
model. I will be using the User model as our default customer in this tutorial. We will also set up an Admin user type with another model Admin.php
which we will set up momentarily.
Now before we can use the authentication all that is needed after running the scaffolding command is to run our migrations. But before we run our migrations for the user model, we want to make a few more migrations to store our new user type.
If you go to database/migrations/
you will see two migrations that come with every Laravel app which build a users table in our database and a passwords table. These tables store our primary users and our “forgot my password” resets. For us to continue on, we need to create a new table to store our second user model, in our case admins because we are creating admins that manage content or something for our example app. We don’t need to make a second table for our passwords, because the two models can share the same passwords table (we will learn about this in Part 5).
So let’s go back to the terminal to generate a migration for a new admins table.
php artisan make:migration create_admins_table --create=admins
This creates a new migration named “create_admins_table” and the --create=
flag tells the scaffolding that we are creating a new table named “admins” so that it can pre-populate the migration for us. This isn’t necessary, but it makes things easier.
Now we need to edit our new migration file to add whatever content we need to store for our admins and generate the table.
<?php use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreateAdminsTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('admins', function (Blueprint $table) { $table->increments('id'); $table->string('name'); $table->string('email')->unique(); $table->string('job_title'); $table->string('password'); $table->rememberToken(); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('admins'); } }
As you see on lines 16-25, i have customized the table for our admins. This is a basic example, but you can add whatever fields you need for your admin. One column worth mentioning is the $table->rememberToken();
this is a special reserved column type in Laravel migrations that sets up the necessary column parameters to accept our “remember me” functionality, you make sure you add this column in the table somewhere. Now, save the migration file and then run the migrations to update our database.
Note: this should go without saying, but make sure you have visited your .env file or config/database.php file and set up the database connection and created an empty database to run the migration before actually running them.
php artisan migrate
Now we have tables set up for both user types. Time to set up the models to talk to these tables.
Setting Up Both Models
The good news is that the primary user model is set up already. We don’t need to do any magic to get this working. You might want to customize the mass-assignable fields in the $fillable
array or customize the table (if you are making a table like “customers” instead of “users”) by editing the $table
attribute. But that is really all you need to worry about to get the first model working.
To create our second model, we will be duplicating the default User.php
model and renaming it to reflect our second user type (in our case Admins). Duplicate it now, and rename it as you wish. I will rename mine Admin.php
.
My Admin.php
code looks like this now:
<?php namespace App; use Illuminate\Notifications\Notifiable; use Illuminate\Foundation\Auth\User as Authenticatable; class Admin extends Authenticatable { use Notifiable; protected $guard = 'admin'; /** * The attributes that are mass assignable. * * @var array */ protected $fillable = [ 'name', 'email', 'password', 'job_title', ]; /** * The attributes that should be hidden for arrays. * * @var array */ protected $hidden = [ 'password', 'remember_token', ]; }
I want to mention a few important parts of this code.
Line 5-6: We need to import Notifiable and Authenticatable. Notifiable is used for allowing us to send notifications to this user type through the Notifiable/Notifications api that Laravel has been using since Laravel 5.3 and doubled down on in Laravel 5.4 (without this most system notifications and packages that send out notifications will not work). Authenticatable on the other hand imports all the authentication code that Laravel ships with, without this you are just creating a normal model, and not a model that you can log in or authenticate against.
Line 10: enables Notifiable as I mentioned above
Line 12: sets the guard that we will authenticate against. This correlates with settings in config/auth.php
and we will be setting this up in the next step. As of right now put whatever you want to call this type of user and remember it. We will set it up next.
The rest of the code in this file is standard model stuff, mainly to handle hidden and fillable fields to protect against mass-assignment. Update the fillable fields in line 20 to correlate with the columns in your table that you created in the migration that you want mass-assigned.
Setting Up Our Guards
Laravel ships with the ability to authenticate against multiple types of users. The way it handles multiple user type authentication is a system called “guards”. We can set up as many of these guards as we want and guards are how we tell Laravel which tables and drivers to use for different user types. Setting up guards is easy, and is the main focus of building a multi-auth setup.
To see the guards Laravel gives you by default, and to create new ones, we can visit our authentication config file. This is located in config/auth.php
. Below you will find an example of this file in its default state with the comments taken out for brevity. The comments on this file are very detailed and worth a read when you apply these changes yourself in your next Laravel project.
<?php return [ 'defaults' => [ 'guard' => 'web', 'passwords' => 'users', ], 'guards' => [ 'web' => [ 'driver' => 'session', 'provider' => 'users', ], 'api' => [ 'driver' => 'token', 'provider' => 'users', ], ], 'providers' => [ 'users' => [ 'driver' => 'eloquent', 'model' => App\User::class, ] ], ... (continues)
In this file we see the defaults at the top. This usually doesn’t need to be messed with, but this defines the default guard to authenticate against if no guard is specified. By default this is set to a guard called “web”.
By reading this file we can see we have two guards created. One guard is called “web” and the other is “api”. Both of these guards use the users provider to access data. Providers are defined in this same file, just below guards, and are basically configuration shorthands that describe how to access data. If we look in the providers array we see the users provider links to the eloquent driver and the App\User
model. This tells Laravel to user Eloquent ORM to interact with the database and use the User model. It basically sets up interacting with the users database.
The only difference between the api and the web guards is the driver they use. The api driver uses a token driver and the web guard uses the session driver. This explains to Laravel how to maintain the authentication. Guards that use the session driver can be remembered using sessions and cookies. This means that users don’t need to log in on every request. Because it uses sessions and cookies however, that means that the user needs to be physically looking at the page and accessing it in a browser. This is where the token driver comes in, the token driver requires authentication on every request via an api token. API authentication is a tutorial for another day, but basically Laravel will look for an api_token field in the header of every request and authenticate a user in for every request they make. This is how an API is handled, and is suitable when you have created an API for your Laravel app. For this tutorial we are focused on the session driver, for users that are navigating the site in a browser.
We can create our new guard for our new user type by appending another array into the Guards array.
<?php return [ 'defaults' => [ 'guard' => 'web', 'passwords' => 'users', ], 'guards' => [ 'web' => [ 'driver' => 'session', 'provider' => 'users', ], 'api' => [ 'driver' => 'token', 'provider' => 'users', ], 'admin' => [ 'driver' => 'session', 'provider' => 'admins', ], 'admin-api' => [ 'driver' => 'token', 'provider' => 'admins', ], ], 'providers' => [ 'users' => [ 'driver' => 'eloquent', 'model' => App\User::class, ], 'admins' => [ 'driver' => 'eloquent', 'model' => App\Admin::class, ], ], ... (continues)
As you can see, this time we will set up a guard called “admin” which correlates with the App\Admin.php
model we set up in the previous step where I defined $guard="admin"
. I will use the session driver and the admins provider.
We need to also set up the admins provider and you can see i did that in the providers array. I linked this provider to my App\Admin::class
model (make sure to get that ::class syntax on the end). For the most part you can always use the eloquent driver. Your other option would be “query_builder” but I don’t see much use to use it unless you were going rogue and had decided to use a different ORM other than eloquent in your project.
So now our guard for admins works. Laravel knows how to authenticate against it. We will be using this guard a lot going forward and you will understand its purpose better as you see how we use guards to declare many aspects of authentication in Laravel.
Testing It
We can test our functionality right now by creating a new view for our admins dashboard. This would represent a page that admin users have access to and customers do not have access to. We will protect it with our new guard so that only admins have access to it.
In your routes/web.php
file, lets create a new route. We will put the url as /admin
and link it to the AdminController@index
.
<?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('/', function () { return view('welcome'); }); Auth::routes(); Route::get('/home', 'HomeController@index'); Route::get('/admin', 'AdminController@index');
Now we need to make an AdminController with an index method. To do this, I will simply duplicate the HomeController that already exists and rename it AdminController.
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; class HomeController extends Controller { /** * Create a new controller instance. * * @return void */ public function __construct() { $this->middleware('auth:admin'); } /** * Show the application dashboard. * * @return \Illuminate\Http\Response */ public function index() { return view('admin'); } }
In this controller it is simply a copy of HomeController, but I made 2 minor changes. First, in the Index function we changed the view to ‘admin’ so that it displays a view named admin (which we haven’t made yet). Lastly, I changed the middleware from “auth” to “auth:admin”. This is how we define the guard to protect this page against. If we simply set the middleware to be “auth” then we will inherit the default guard that you saw in the config/auth.php
file earlier (in this case Users). So if we want to authenticate against a different guard, then we define it after a colon. So “auth:admin” says to display the page only to logged in admin users. If we used “auth:api” then it would authenticate against the “api” guard.
So by setting this to the admin guard in the middleware, we know that when we try to access this /admin
url that it will require us to be logged in as an admin.
Lets create the “admin” view now and test this. Create a view in /resources/views/admin.blade.php
. I made this by duplicating the home.blade.php
file that is already in there and renaming it admin.blade.php
. This is easy for demonstration purposes. I won’t show the code here, it is just a view file, with plain HTML. There isn’t anything relevant to the tutorial in the view code. Any HTML would work the same. The protection, requiring admin access happens at the controller level, not the view level.
Now let’s test our app in the browser. Register a new user by clicking the “Register” button and filling out the form. This will create a new “User” (the default user type) and log us in. Once logged in, we should have access to the /home
url, because that is the user dashboard (you wouldn’t have access to this if you were logged out. But now if we go to the /admin
url, we will get redirected back to /home
and we will not have access to this page. This shows that our admin guard is working. We can not access the /admin
unless we are logged in as an admin.
What’s Next?
This series is a 5 part series about completing the setup of Multi-Authentication in Laravel 5.4+. To continue this tutorial, please skip to the next part that interests you.
Part 1: (This Page) Setting up multiple models
Part 2: Views and Routes for Second Model
Part 3: Editing Authentication Middleware and Redirects
Part 4: Logging users out
Part 5: Forgot my Password Customization
Hi Alex, can you make Laravel Restful API tutorial?
Thanks for the post.
I wanted to know what you use for syntax highlighting on your blog posts.
part one was very insightful and well explained. unfortunately the links to part two do not exist? but why? this was looking like the best tutorial on the subject i found out there. too bad its half done
sir, data of both form going into users table . admin data not going in admins table.
where i should change?
i followed the tutorial and now everything works fine. but i want the admin to be able to post a blog and the blog should be associated with the admin’s id. how do i get the Id of the admin?
where is the second part ??
where is the second part?
Where is the part 2? 🙁
hello i really like your multi authentication tutorial….
i would really appreciate if you could also make a tutorial about the multi registration because i have a problem about it .. thanks in advance
i want any link about the multi registration for multi auth
Hi curt laravel 5.5 does not have such kind of exception in app exception handle and it doesn’t use use loops. Do you have a work around on redirecting to return to the correct login page for mult Auth? I will Appreciate
where is the second part
Using Laravel Passport is a much easier way of authenticating token in Laravel application (https://www.cloudways.com/blog/rest-api-laravel-passport-authentication/ ) . Instead of JWT, use Passport.
Hi, just came her to thank you for all the effort you put into making tutorial videos.
thanks for this tuto 🙂
Pingback: Laravel Multiple Login Logout Password Reset User/Member and Admin Tutorial - Ken Teo's Blog
Nice tutorial. I tried several others but they all skipped steps and/or didn’t explain everything clearly, like this one does, and I could never quite get it working
Hello Great tutorial, completed all videos but i was facing problem while Posting fr admin account to database
$post->user_id = auth()->user()->id; // default
$post->admin_id= auth()->admin()->id;//my code
i gave a admin id and every thing but i was getting error at this particular position i don’t know what to do could you please help me.
i defined this in Post.php which i created to post.
public function admin(){
return $this->belongsTo(‘App\Admin’);
}
public function user(){
return $this->belongsTo(‘App\User’);
}
Instead of using
auth()->admin()->id()
tryAuth::guard('admin')->id()
orAuth::guard('admin')->user()->id()
. You need to identify that you are requesting the “admin” guard.Hi Alex,
thanks for this tutorial.
Did you try to test it with phpUnit ?
i wrote several tests but when i try to simulate admin with “$this->actingAs($admin, ‘admin’)”, the tests doesn’t match the reality
in my test, acting a admin, i have a 200 response when i try to access “/home” witch is the user space page
in reality, logged as an admin, i am redirected to /login when i try to access “/home”
hi
i completed the first tutorial, it is very good. How can i register an admin
so that i can test if he can access the page admin? When i understand it correctly,
the admin should not have access to the home page, is this correct ?
Where are the other 4 parts of the tutorial ? i need them.
Hi Sir, i follow your tutorial until part 4, and i have trouble with Auth guard.
Let say i use @if (Auth::guard(‘web’)->check())
Logout user
@else
echo Logout admin
@endif
but if user and admin is login in same computer, the first if will be always true. So to solve this problem ?
Sorry for my bad english.
Hi Sir, i follow your tutorial until part 4, and i have trouble with Auth guard.
Let say i use @if (Auth::guard(‘web’)->check())
Logout user
@else
echo Logout admin
@endif
but if user and admin is login in same computer, the first if will be always true. So how to solve this problem ?
Sorry for my bad english.
Hello and thank you for this tutorial.
when I am logged in as user and i click on the link forget my password (admin) i am redirected to the home page user. help me please.
cannot find the other parts of multi authentication
The need to be re-written with the newest version of Laravel now
I was looking for the description of the remaining parts of the multi authentication videos
The need to be re-written with the newest version of Laravel now
Hey Hello nice Tutorial , wanted to ask what happening with the advance blog tutorial, please can you finish the tutorial because it was really great