How To Create a Custom Auth Driver in Laravel 4

I recently worked on a project where we needed to authenticate users using a SOAP webservice. (Yes, SOAP). Since we were building the app with Laravel we decided to create a custom authentication driver. By creating a custom driver you get to use all the functions you are used to, like Auth::attempt(), Auth::user(), Auth::check() etc. It's really easy to get started.

Let's start by creating a folder structure to store our files. You can store the provider where you want, but I recommend setting up a logical structure like this.

/app
    /Project
        /Providers
            /AuthUserProvider.php

Then we add the project folder to the composer.json classmap so that our files get autoloaded. Remember to run a composer dumpautoload after.

"autoload": {
    "classmap": [
        "app/commands",
        "app/controllers",
        "app/models",
        "app/database/migrations",
        "app/database/seeds",
        "app/tests/TestCase.php",
        "app/Project"
    ]
},

Next we have to create our class. Every authentication driver has to implement a UserProviderInterface. The interface requires that our class implements these functions:

public function retrieveById($identifier);
public function retrieveByCredentials(array $credentials);
public function validateCredentials(UserInterface $user, array $credentials);

First we create our namespace and define the classes we need from Laravel.

<?php namespace Project\Providers;

use Illuminate\Auth\UserProviderInterface;
use Illuminate\Auth\GenericUser;

Then we start creating our class. Remember we have to implement the UserProviderInterface.

class AuthUserProvider implements UserProviderInterface {

In this example we will be authenticating our user from an external webservice, so we create a private variable for it.

  /**
  * External webservice for authentication
  */
  private $webservice;

We also create a user variable where we will store the user object.

  /**
  * The user object.
  */
  private $user;

Next we set up our constructor that injects our webservice and defaults the user to null.

  /**
  * Constructor
  *
  * @return void
  */
  public function __construct(\Project\Webservice\Auth $webservice)
  {
      $this->webservice = $webservice;
      $this->user = null;
  }

Let's start by creating the first function. This function is exectuted when you do Auth::user() and returns the user object. We first check if the user is already fetched, so we only hit the webservice once per request. Note that this function requires that you return an id key.

  /**
  * Retrieves a user by id
  *
  * @param int $identifier
  * @return mixed null|array
  */
  public function retrieveByID($identifier)
  {
      $this->user = is_null($this->user) ? $this->webservice->find($identifier) : $this->user;
      return $this->user;
  }

Next we create the function that checks whether a user exists.

  /**
  * Tries to find a user based on the credentials passed.
  *
  * @param array $crendtials username|password
  * @return mixed bool|UserInterface
  */
  public function retrieveByCredentials(array $credentials)
  {
      if(!$user = $this->webservice->find($credentials['username'])) return false;

      return new GenericUser($user);
  }

Lastly we create the last function that checks if the user has passed the correct credentials and are cleared to be let in.

    /**
     * Validates the credentials passed to the ones in webservice.
     *
     * @param UserInterface $user
     * @param array $credentials
     * @return bool
     */
    public function validateCredentials(\Illuminate\Auth\UserInterface $user, array $credentials)
    {
      return $this->webservice->validateCredentials($credentials['password'], $user->password);
    }
}

Link to the full class https://gist.github.com/antonigiske/1baf1523ea7802a82404

Now that we have created the class we have to tell Laravel we have a brand new authentication driver. A good place to put this is in app/start/global.php like so:

Auth::extend('customAuth', function($app) {
    $provider = new \Project\Providers\AuthUserProvider(new \Project\Webservice\Auth());
    return new \Illuminate\Auth\Guard($provider, $app['session.store']);
});

The last thing we have to do in order to test our authentication driver is to enable it in app/config/auth.php.

'driver' => 'customAuth',

You are now the proud owner of your very own authentication driver. Please leave a comment if you have any feedback or questions.


comments powered by Disqus