Laravel Auth Tutorial

 

Most websites will need a way to allow users to log in so that they can access resources, update information, and so on. Some frameworks like Codeigniter do not have a built in authentication system. In a scenario like that, you would have to write your own, or implement a third party solution. With Laravel, user authentication is baked right in. Let’s take a look at how we can put Laravel Auth to use!
Set Up a Demo App

The first thing we’ll do is to just set up a demo laravel application on our machine. In this case we are using windows with wamp server. I know, yell at me, throw tomatoes, do whatever you like! One day I will get my own dedicated machine with OSX and all the goodies installed. I’ll also make time to get up to speed with Homestead and Vagrant. For now, we’ll make do with our trusty setup since it is working fine, and hey, if it works – it’s good for me. First off, I’ll download the laravel.phar file from the quick start page at Laravel. We’ll put this in the www root folder. Now, we can CD into www and run php laravel.phar new authdemo

note: If your setup bugs out with something like, “The PHP cURL extension must be installed to use Guzzle“, you’ll need to make sure the line extension=php_curl.dll is uncommented in your php.ini file. Basically, remove the ; before it, save, and restart all services. Now run php laravel.phar new authdemo again and you should find that, yes we are ready for action when you see:
C:wampwww>php laravel.phar new authdemo
Crafting application…
Application ready! Build something amazing.

Nice! Go ahead and hit http://localhost/authdemo/public/ to make sure you see the familiar arrival message.
Laravel Auth
Configure The Users Table

Out of the box, Eloquent is the authentication driver for Laravel. You don’t have to use this, but then again, you’re using Laravel so let’s use the defaults. You’ll find this in the auth.php file located in the app/config folder.

Let’s create a table to work with using Jeffrey Ways Generator package. Don’t forget to add it to your composer.json file as well as the app/config/app.php file in the service providers array. This is the entry to add to the array 'WayGeneratorsGeneratorsServiceProvider'

Your composer.json might look something like:

{
    "name": "laravel/laravel",
    "description": "The Laravel Framework.",
    "keywords": ["framework", "laravel"],
    "license": "MIT",
    "require": {
        "laravel/framework": "4.2.*",
         "way/generators": "dev-master"
    },
    "autoload": {
        "classmap": [
            "app/commands",
            "app/controllers",
            "app/models",
            "app/database/migrations",
            "app/database/seeds",
            "app/tests/TestCase.php"
        ]
    },
    "scripts": {
        "post-install-cmd": [
            "php artisan clear-compiled",
            "php artisan optimize"
        ],
        "post-update-cmd": [
            "php artisan clear-compiled",
            "php artisan optimize"
        ],
        "post-create-project-cmd": [
            "php artisan key:generate"
        ]
    },
    "config": {
        "preferred-install": "dist"
    },
    "minimum-stability": "stable"
}

   
{
    "name": "laravel/laravel",
    "description": "The Laravel Framework.",
    "keywords": ["framework", "laravel"],
    "license": "MIT",
    "require": {
        "laravel/framework": "4.2.*",
         "way/generators": "dev-master"
    },
    "autoload": {
        "classmap": [
            "app/commands",
            "app/controllers",
            "app/models",
            "app/database/migrations",
            "app/database/seeds",
            "app/tests/TestCase.php"
        ]
    },
    "scripts": {
        "post-install-cmd": [
            "php artisan clear-compiled",
            "php artisan optimize"
        ],
        "post-update-cmd": [
            "php artisan clear-compiled",
            "php artisan optimize"
        ],
        "post-create-project-cmd": [
            "php artisan key:generate"
        ]
    },
    "config": {
        "preferred-install": "dist"
    },
    "minimum-stability": "stable"
}

Once all this is complete run composer update, then run php artisan generate:migration create_users_table --fields="username:string, email:string:unique, password:string"

Before we forget, lets make sure our database connections are configured in app/config/database.php. Since we are rebels in the local environment, we’re just going to use root with no password

PHP
        'mysql' => array(
            'driver'    => 'mysql',
            'host'      => 'localhost',
            'database'  => 'authdemo',
            'username'  => 'root',
            'password'  => '',
            'charset'   => 'utf8',
            'collation' => 'utf8_unicode_ci',
            'prefix'    => '',
        )

   
        'mysql' => array(
            'driver'    => 'mysql',
            'host'      => 'localhost',
            'database'  => 'authdemo',
            'username'  => 'root',
            'password'  => '',
            'charset'   => 'utf8',
            'collation' => 'utf8_unicode_ci',
            'prefix'    => '',
        )

While we’re at it, let’s have a look at the migration which was created for us by using the generate command.

PHP
<?php

use IlluminateDatabaseMigrationsMigration;
use IlluminateDatabaseSchemaBlueprint;

class CreateUsersTable extends Migration {

    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('users', function(Blueprint $table)
        {
            $table->increments('id');
            $table->string('username');
            $table->string('email')->unique();
            $table->string('password');
            $table->timestamps();
        });
    }


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

}

   
<?php

use IlluminateDatabaseMigrationsMigration;
use IlluminateDatabaseSchemaBlueprint;

class CreateUsersTable extends Migration {

    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('users', function(Blueprint $table)
        {
            $table->increments('id');
            $table->string('username');
            $table->string('email')->unique();
            $table->string('password');
            $table->timestamps();
        });
    }


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

}

Looks good to me! php artisan migrate

Oh wow, this is new! Jeff must have updated his generators package, I don’t remember the nice alert – nice touch.
**************************************
* Application In Production! *
**************************************

Do you really wish to run this command? y
Migration table created successfully.
Migrated: 2014_07_14_210221_create_users_table

We simply choose y and proceed to complete the process like you see above.
Populate the Users Table

Now that we have set up some important boilerplate type code, we can populate the table with some data. Now here is something really cool – the php artisan tinker command! You can invoke this process from the command line and use it to hook into the Laravel Application to run simple scripts using Laravel. Instead of creating a new php file, saving, then running in your browser – you can simply use php artisan tinker to bang out some quick logic.

php artisan tinker
Full REPL not supported. Falling back to simple shell.
>$user = new User;
>$user->username = ‘Vegibit’;
>$user->email = ‘vegibit@example.com’;
>$user->password = Hash::make(‘haha’);
>$user->save();
>^C

It looks like we ran into a little hiccup. It turns out the latest version of Laravel uses the Boris repo to power tinker. This requires the pcntl functions which need a *nix system. The tinker command does fall back to the 4.0 version, so it appears some things will still work. After completing the above code, we do see that our database became populated – so it looks like at least this snippet did work!

laravel artisan tinker

Onward! Ok, now that we have a user in the Users table, we’re going to need a form to allow someone to log in. We can use a route resource to accomplish this goal. Let’s set up the routes file like so:

PHP
<?php

/*
|--------------------------------------------------------------------------
| Application Routes
|--------------------------------------------------------------------------
|
| Here is where you can register all of the routes for an application.
| It's a breeze. Simply tell Laravel the URIs it should respond to
| and give it the Closure to execute when that URI is requested.
|
*/

Route::get('login', 'SessionsController@create');
Route::get('logout', 'SessionsController@destroy');
Route::resource('sessions', 'SessionsController');

   
<?php

/*
|--------------------------------------------------------------------------
| Application Routes
|--------------------------------------------------------------------------
|
| Here is where you can register all of the routes for an application.
| It's a breeze. Simply tell Laravel the URIs it should respond to
| and give it the Closure to execute when that URI is requested.
|
*/

Route::get('login', 'SessionsController@create');
Route::get('logout', 'SessionsController@destroy');
Route::resource('sessions', 'SessionsController');

We can view our routes using php artisan routes
+--------+-----------------------------------+------------------+----------------------------+----------------+---------------+
| Domain | URI                               | Name             | Action                     | Before Filters | After Filters |
+--------+-----------------------------------+------------------+----------------------------+----------------+---------------+
|        | GET|HEAD login                    |                  | SessionsController@create  |                |               |
|        | GET|HEAD logout                   |                  | SessionsController@destroy |                |               |
|        | GET|HEAD sessions                 | sessions.index   | SessionsController@index   |                |               |
|        | GET|HEAD sessions/create          | sessions.create  | SessionsController@create  |                |               |
|        | POST sessions                     | sessions.store   | SessionsController@store   |                |               |
|        | GET|HEAD sessions/{sessions}      | sessions.show    | SessionsController@show    |                |               |
|        | GET|HEAD sessions/{sessions}/edit | sessions.edit    | SessionsController@edit    |                |               |
|        | PUT sessions/{sessions}           | sessions.update  | SessionsController@update  |                |               |
|        | PATCH sessions/{sessions}         |                  | SessionsController@update  |                |               |
|        | DELETE sessions/{sessions}        | sessions.destroy | SessionsController@destroy |                |               |
+--------+-----------------------------------+------------------+----------------------------+----------------+---------------+

   
+--------+-----------------------------------+------------------+----------------------------+----------------+---------------+
| Domain | URI                               | Name             | Action                     | Before Filters | After Filters |
+--------+-----------------------------------+------------------+----------------------------+----------------+---------------+
|        | GET|HEAD login                    |                  | SessionsController@create  |                |               |
|        | GET|HEAD logout                   |                  | SessionsController@destroy |                |               |
|        | GET|HEAD sessions                 | sessions.index   | SessionsController@index   |                |               |
|        | GET|HEAD sessions/create          | sessions.create  | SessionsController@create  |                |               |
|        | POST sessions                     | sessions.store   | SessionsController@store   |                |               |
|        | GET|HEAD sessions/{sessions}      | sessions.show    | SessionsController@show    |                |               |
|        | GET|HEAD sessions/{sessions}/edit | sessions.edit    | SessionsController@edit    |                |               |
|        | PUT sessions/{sessions}           | sessions.update  | SessionsController@update  |                |               |
|        | PATCH sessions/{sessions}         |                  | SessionsController@update  |                |               |
|        | DELETE sessions/{sessions}        | sessions.destroy | SessionsController@destroy |                |               |
+--------+-----------------------------------+------------------+----------------------------+----------------+---------------+

We can now generate a controller that will handle all the routes we just set up using php artisan generate:controller SessionsController

Friendly Alert! In this episode we are using the RESTful development style. If the routes above look like a foreign language, check out our episode on RESTful Controllers and you’ll be good to go.

Here is our new controller in all of its glory:

PHP
<?php

class SessionsController extends BaseController {

    /**
     * Display a listing of the resource.
     * GET /sessions
     *
     * @return Response
     */
    public function index()
    {
        //
    }

    /**
     * Show the form for creating a new resource.
     * GET /sessions/create
     *
     * @return Response
     */
    public function create()
    {
        return View::make('sessions.create');
    }

    /**
     * Store a newly created resource in storage.
     * POST /sessions
     *
     * @return Response
     */
    public function store()
    {
        //
    }

    /**
     * Display the specified resource.
     * GET /sessions/{id}
     *
     * @param  int  $id
     * @return Response
     */
    public function show($id)
    {
        //
    }

    /**
     * Show the form for editing the specified resource.
     * GET /sessions/{id}/edit
     *
     * @param  int  $id
     * @return Response
     */
    public function edit($id)
    {
        //
    }

    /**
     * Update the specified resource in storage.
     * PUT /sessions/{id}
     *
     * @param  int  $id
     * @return Response
     */
    public function update($id)
    {
        //
    }

    /**
     * Remove the specified resource from storage.
     * DELETE /sessions/{id}
     *
     * @param  int  $id
     * @return Response
     */
    public function destroy($id)
    {
        //
    }

}

   
<?php

class SessionsController extends BaseController {

    /**
     * Display a listing of the resource.
     * GET /sessions
     *
     * @return Response
     */
    public function index()
    {
        //
    }

    /**
     * Show the form for creating a new resource.
     * GET /sessions/create
     *
     * @return Response
     */
    public function create()
    {
        return View::make('sessions.create');
    }

    /**
     * Store a newly created resource in storage.
     * POST /sessions
     *
     * @return Response
     */
    public function store()
    {
        //
    }

    /**
     * Display the specified resource.
     * GET /sessions/{id}
     *
     * @param  int  $id
     * @return Response
     */
    public function show($id)
    {
        //
    }

    /**
     * Show the form for editing the specified resource.
     * GET /sessions/{id}/edit
     *
     * @param  int  $id
     * @return Response
     */
    public function edit($id)
    {
        //
    }

    /**
     * Update the specified resource in storage.
     * PUT /sessions/{id}
     *
     * @param  int  $id
     * @return Response
     */
    public function update($id)
    {
        //
    }

    /**
     * Remove the specified resource from storage.
     * DELETE /sessions/{id}
     *
     * @param  int  $id
     * @return Response
     */
    public function destroy($id)
    {
        //
    }

}

We’ll populate the create method like so:

PHP
    public function create()
    {
        return View::make('sessions.create');
    }

   
    public function create()
    {
        return View::make('sessions.create');
    }

Now we need to create the actual form to handle this. We’ll create a master page and embed bootstrap so things look better than bare html. Here is a starting point for the master page and the form. With the laravel form class, you can specify classes to add via an array. For any html elements that laravel is generating for the form, we will add the class using the array. Any other elements we’ll just add the class in the view file.
default.blade.php

XHTML
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Laravel Auth Tutorial</title>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">

<!-- Optional theme -->
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css">

<!-- Latest compiled and minified JavaScript -->
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
</head>

<body>
<div class="container">
  <div>
    <h1>Laravel Auth Tutorial</h1>
  </div>

@yield('content')

</div>
</body>

</html>

   
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Laravel Auth Tutorial</title>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">

<!-- Optional theme -->
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css">

<!-- Latest compiled and minified JavaScript -->
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
</head>

<body>
<div class="container">
  <div>
    <h1>Laravel Auth Tutorial</h1>
  </div>

@yield('content')

</div>
</body>

</html>

create.blade.php

XHTML
@extends('layouts.default')

@section('content')
{{ Form::open(array('route' => 'sessions.store', 'class'=>'form-horizontal' )) }}

<div class="form-group">
<div class="col-lg-1">
{{ Form::label('email', 'Email:') }}
</div>

<div class="col-lg-7">
{{ Form::text('email', '', array('class' => 'form-control')) }}
</div>
</div>

<div class="form-group">
<div class="col-lg-1">
{{ Form::label('password', 'Password:') }}
</div>

<div class="col-lg-7">
{{ Form::password('password', array('class' => 'form-control')) }}
</div>
</div>

<div class="form-group">
<div class="col-lg-8">
{{ Form::submit('Login', array('class' => 'btn btn-lg btn-info btn-block')) }}
</div>
</div>

{{ Form::close() }}
@stop

   
@extends('layouts.default')

@section('content')
{{ Form::open(array('route' => 'sessions.store', 'class'=>'form-horizontal' )) }}

<div class="form-group">
<div class="col-lg-1">
{{ Form::label('email', 'Email:') }}
</div>

<div class="col-lg-7">
{{ Form::text('email', '', array('class' => 'form-control')) }}
</div>
</div>

<div class="form-group">
<div class="col-lg-1">
{{ Form::label('password', 'Password:') }}
</div>

<div class="col-lg-7">
{{ Form::password('password', array('class' => 'form-control')) }}
</div>
</div>

<div class="form-group">
<div class="col-lg-8">
{{ Form::submit('Login', array('class' => 'btn btn-lg btn-info btn-block')) }}
</div>
</div>

{{ Form::close() }}
@stop

Cool! Let’s go ahead and load up http://localhost/authdemo/public/login to see how things are coming along:
laravel auth login

Shweet!
Update SessionsController

So we have a form going, and things look to be routing properly. We’ll now need to update the SessionsController so that the store method will handle a login once a user fills out the form and clicks login. We’ll set up some logic so that both the login and logout routes will handle their requests when visited. Another thing to note, we are going to need to update our migrations to include $table->text('remember_token')->nullable();, otherwise the Redirect::to(); after the Auth::logout(); will fail as I found out 🙂

This seemed to work, your mileage may vary:
run php artisan migrate:make users_add_remembertoken

Add this code to your new migration file:

PHP
<?php

use IlluminateDatabaseSchemaBlueprint;
use IlluminateDatabaseMigrationsMigration;

class UsersAddRemembertoken extends Migration {

    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table("users", function($table) {
           
            $table->text('remember_token')->nullable();
           
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        //
    }

}

   
<?php

use IlluminateDatabaseSchemaBlueprint;
use IlluminateDatabaseMigrationsMigration;

class UsersAddRemembertoken extends Migration {

    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table("users", function($table) {
           
            $table->text('remember_token')->nullable();
           
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        //
    }

}

run php artisan migrate

If you still have troubles, update your User.php model like so:

PHP
<?php

use IlluminateAuthUserTrait;
use IlluminateAuthUserInterface;
use IlluminateAuthRemindersRemindableTrait;
use IlluminateAuthRemindersRemindableInterface;

class User extends Eloquent implements UserInterface, RemindableInterface {

    use UserTrait, RemindableTrait;

    /**
     * The database table used by the model.
     *
     * @var string
     */
    protected $table = 'users';

    /**
     * The attributes excluded from the model's JSON form.
     *
     * @var array
     */
    protected $hidden = array('password', 'remember_token');
   
    public function getRememberToken()
    {
        return $this->remember_token;
    }
   
    public function setRememberToken($value)
    {
        $this->remember_token = $value;
    }
   
    public function getRememberTokenName()
    {
        return 'remember_token';
    }

}

   
<?php

use IlluminateAuthUserTrait;
use IlluminateAuthUserInterface;
use IlluminateAuthRemindersRemindableTrait;
use IlluminateAuthRemindersRemindableInterface;

class User extends Eloquent implements UserInterface, RemindableInterface {

    use UserTrait, RemindableTrait;

    /**
     * The database table used by the model.
     *
     * @var string
     */
    protected $table = 'users';

    /**
     * The attributes excluded from the model's JSON form.
     *
     * @var array
     */
    protected $hidden = array('password', 'remember_token');
   
    public function getRememberToken()
    {
        return $this->remember_token;
    }
   
    public function setRememberToken($value)
    {
        $this->remember_token = $value;
    }
   
    public function getRememberTokenName()
    {
        return 'remember_token';
    }

}

We can now update the store and destroy methods like so:
store()

PHP
    public function store()
    {
        $input = Input::all();

        $attempt = Auth::attempt( array('email' => $input['email'], 'password' => $input['password']) );
       
        if($attempt) {
            return Redirect::to('user');
        } else {
            return Redirect::to('login');
        }
    }

   
    public function store()
    {
        $input = Input::all();

        $attempt = Auth::attempt( array('email' => $input['email'], 'password' => $input['password']) );
       
        if($attempt) {
            return Redirect::to('user');
        } else {
            return Redirect::to('login');
        }
    }

destroy()

PHP
    public function destroy()
    {
        Auth::logout();
        Session::flush();
        return Redirect::to('login');
       
    }

   
    public function destroy()
    {
        Auth::logout();
        Session::flush();
        return Redirect::to('login');
       
    }

We won’t do anything too fancy, if the user is logged out, we’re just going to send her back to the login form. You could do all kinds of nice things with custom views for different scenarios and so on, but we just want to see the authentication login and logout functionality of laravel at work here. We’ll set up a user view and update the routes file now.
user.blade.php

XHTML
@extends('layouts.default')

@section('content')
<div class="col-lg-8">
<h4 class="alert alert-success">Hi there friend! Thanks for registering your email of  {{ Auth::user()->email }} </h4>
</div>
@stop
   
@extends('layouts.default')

@section('content')
<div class="col-lg-8">
<h4 class="alert alert-success">Hi there friend! Thanks for registering your email of  {{ Auth::user()->email }} </h4>
</div>
@stop

updated routes.php

PHP
<?php

/*
|--------------------------------------------------------------------------
| Application Routes
|--------------------------------------------------------------------------
|
| Here is where you can register all of the routes for an application.
| It's a breeze. Simply tell Laravel the URIs it should respond to
| and give it the Closure to execute when that URI is requested.
|
*/

Route::get('user', function() {
    return View::make('sessions/user');
})->before('auth');

Route::get('login', 'SessionsController@create');
Route::get('logout', 'SessionsController@destroy');
Route::resource('sessions', 'SessionsController');

<?php

/*
|--------------------------------------------------------------------------
| Application Routes
|--------------------------------------------------------------------------
|
| Here is where you can register all of the routes for an application.
| It's a breeze. Simply tell Laravel the URIs it should respond to
| and give it the Closure to execute when that URI is requested.
|
*/

Route::get('user', function() {
    return View::make('sessions/user');
})->before('auth');

Route::get('login', 'SessionsController@create');
Route::get('logout', 'SessionsController@destroy');
Route::resource('sessions', 'SessionsController');

Ok, pretty standard stuff. You’ll note that we do make use of ->before(‘auth’); and all this does is tell laravel, if a user tries to hit the user route, send them packing if they’re not logged in. We’re ready for action.

First we’ll visit http://localhost/authdemo/public/login and fill in our information to login.
laravel auth login
Now we are redirected to http://localhost/authdemo/public/user, looks great!
laravel auth login success

Finally, we’ll visit http://localhost/authdemo/public/logout which will log us out and redirect us right back to the login form like so.
laravel auth login


Fantastic work y’all!! We now have a working demo of authentication in laravel! We covered many of the key topics and commands in dealing with setting up authentication in laravel such as php artisan generate:migration, php artisan migrate, php artisan tinker, php artisan routes, php artisan generate:controller, Input::all();, Auth::attempt();, Auth::logout();, Redirect::to(); and Session::flush();