Laravel Auth — how does it happen?

Syed Sirajul Islam Anik
5 min readSep 28, 2017

--

Image from: https://www.unifiedinfotech.net/wp-content/uploads/2016/05/How-Laravel-Eases-The-Process-of-Web-Development-Unified-Infotech.jpg

Laravel is definitely a good framework. That’s what people say. I can’t disagree. The only framework I know and I code. I didn’t even write any project with raw PHP. I have been working with PHP since 2013 September. I can still remember that. I learnt python before PHP. Someone said Python & Django has great demand on job market. One of the mostly paid jobs. At the end of the day salary matters (for almost everybody). So I moved from Java (I don’t like java that much) to Python. Learnt python, did some coding. Mean time, I had to show a project to my university teacher, a web application. Didn’t know how to implement using python. Someone said before you move to django, learn MVC. Damn. That’s not easy for me. Overwhelming thing. Then I thought to give a try to PHP. And after then since now, I couldn’t move from PHP to any other language. It’s a story. Will take the whole night if you read. Let’s move to the main points now.

Laravel, that works like magic. Obviously true. As I only know Laravel as a framework, I can’t argue over the learning curve about other frameworks. If you just want to get the job done it is simple enough to do with Laravel. Under the hood, it works so many things. I was working on a project where I wanted to use Auth facade to validate & get the user. But the project’s database structure was different. So I had to dig in how Laravel’s Auth works. You can read the article — Laravel API — Authenticate user with custom driver & different table using auth middleware. So I will try to explain what I have learned.

Laravel boots the application when a request is passed to public/index.php. It loads up the application from bootstrap/app.php.

<?php
// laravel 5.5.0 - line:38
// public/index.php
$app = require_once __DIR__.’/../bootstrap/app.php’;

In bootstrap/app.php it instantiates Illuminate\Foundation\Application. If you just look into that class constructor, you’ll see that it registers base service providers & core container aliases. Inside the registerCoreContainerAliases method, it registers the core container aliases. The first element of the array values are the concrete class those are resolved later under the hood for the facades to work.

For the Auth Facade or app(‘auth’) or the app()->make(‘auth’) the underlying class is Illuminate\Auth\AuthManager. So, all the calls we make through these, AuthManager is going to handle those calls.

  1. First things first, A web browser initiates a call to server. (So many things here, I want to how! Check the link included.)
  2. index.php inside the public folder gets the request. (Apache/Nginx thing. All calls redirected to index.php file.)
  3. Loads bootstrap/app.php inside the project.
  4. Illuminate\Foundation\Application instantiated. Does whatever is said to do. Loads containers, basic service providers & container aliases.
  5. Besides many things, It creates a singleton of App\Http\Kernel which is actually an extension (inheritance) of lluminate\Foundation\Http\Kernel.
  6. Comes back to public/index.php, makes (resolves) instance of Illuminate\Contracts\Http\Kernel and in return gets App\Http\Kernel.
  7. Calls the handle method of the resolved kernel (inside Illuminate\Foundation\Http\Kernel).
  8. Call moves to sendRequestThroughRouter method. Checks if the middleware should be skipped or not (On test cases while using Illuminate\Foundation\Testing\WithoutMiddleware trait). If not then pipes through the middlewares. If you want to know what Pipelining is in Laravel, check THIS LINK. Before checking any route/named middleware, it checks these Middlewares first. Check the middleware list here.
  9. Pipelining through all the middlewares, it dispatches to router class.
  10. Then the router class tries to match the ROUTE. By default, for web Laravel loads 6 middlewares & for api it loads 2 middlewares. From the route it tries to get the route middleware (if added). Again pipelines the middlewares for the current route.

Where is the AUTH?

Suppose we have two routes like below,

<?php
// routes/web.php
Route::get('users', 'UserController@getUsers')->middleware('auth');
// routes/api.php
Route::get('users', 'UserController@getUsers')->middleware('auth:api');

As I said before after coming to 10, it finds that the route has any assigned middlewares. For our example auth middleware applied to it. The responsibility of auth middleware is handled by the Illuminate\Auth\Middleware\Authenticate class (A link is attached to it). Now, the Authenticate middleware gets to run and the handle method is fired from the pipeline. (You’ll get to know about this from the linked article above or from code).

  1. After coming to Authenticate::handle the call is moved to authenticate method of the same class.
  2. Checks if any guard (auth:web, auth:api) is assigned or not. If not, then the AuthManager::authenticate is called which in turn becomes like $this->guard()->{$method}(…$parameters); //or $this->guard()->authenticate()(methods are on AuthManager). Or if any guard is applied checks for the first guard which can return an user.

Here, guard method inside the AuthManager class is the decider of which guard to use. It resolves which provider to use. If no guard is given for the auth, then it takes the default guard driver from config/auth.php. When it tries to resolve the guard, it checks if any guard name is defined inside the config/auth.php within the key guards. If found, it checks if it is a custom created guard or not. If yes, then calls the custom created auth guard with the app instance, name of the guard and configuration stored in config/auth.php for the guard. And if not custom, it tries to check if any shipped guard was used with ‘createGuard_driver_from_configDriver’ method. If you use session driver for the guard, then createSessionDriver method will be called or createTokenDriver for the token driver. Both of them creates instance an implementation of Illuminate\Contracts\Auth\UserProvider based on the provider driver which is responsible for the authentication & user’s operation based on credentials.

If the guard method mentioned on previous paragraph can return a TRUTHY value, then that GUARD for which the truthy value was returned will be used throughout the application’s lifetime. If a FALSELY value was returned, then the middleware will assume that the user cannot be authenticated, and throws AuthenticationException.

So far I tried to show you how the full middleware part is checked. BTW, the guard middleware is also the same but does the reverse thing. The auth middleware checks if the user can log in and the guest middleware checks if the user can log it, he is not permitted. Just check the class and you’ll get it easily now.

[
// ...
'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
// ...
]

That’s it for now. If you think I messed up or it’s actually wrong, let me know. I will try to update it. Thanks.

--

--

Syed Sirajul Islam Anik

software engineer with "Senior" tag | procrastinator | programmer | !polyglot | What else 🙄 — Open to Remote