LDAP authentication with Laravel and Adldap2

This post provides a short tutorial on integrating LDAP authentication with the Laravel framework. One of my recent projects has involved adding LDAP authentication to a Laravel web app using Steve Bauman’s excellent Adlap2 package.

Lightweight Directory Access Protocol (LDAP) needs no introduction and any developer who has spent time working on internal ‘enterprise’ software project will have encountered it. Simple integration might just focus on using an LDAP directory to authenticate users using a common username and password across a suite of enterprise applications. More advanced integration work might including binding to a driectory for interactive retrieval of corporate contact data or delegated management of groups and roles.

If you’re planning to use this tutorial to add LDAP support to an existing project some of the set-up and config may vary. It is assumed that you’re working Laravel’s built-in authentication scaffolding as it will be easier to demonstrate how Adldap2 can be layered onto an existing. I’m also assuming that you’re developing with Homestead but that doesn’t matter too much.

  1. First up, we need to satisfy a dependency on the php-ldap extension. This might seem obvious but version of the ldap extension must exactly match the version of PHP installed in your Homestead environment. At the time of writing, this is v7.2 but you might need to alter depending on your set-up.
    $sudo apt-get update
    $sudo apt-get install -y php7.2-ldap
    $php -v | grep ldap

    Once installed you will want to restart the Nginx web server to ensure the ldap extension is loaded. The easiest way to accomplish this is by running `vagrant provision` from your host’s Homestead directory.

  2. Next, use Artisan to create Laravel’s built-in authentication scaffolding. The Laravel auth scaffold is practically bullet-proof for most out-of-box app requirements and serves as an excellent starting point for LDAP integration with Adldap2.
    $php artisan make:auth
    $php artisan migrate


  3. Access to password recovery functions probably won’t make much sense for common LDAP authentication scenarios, so unless you are planning to support a mix of local Laravel authentication and LDAP, you might want to consider limiting the built-in routes. The following routing should work for most cases, but you might want to customise to suit your needs. Note that I’ve applied a middleware authentication restriction in these routes to protect the ‘/home’ route.
    $ php artisan route:list
    | Domain | Method   | URI                  | Name          | Action                                                  | Middleware   |
    |        | GET|HEAD | /                    |               | Closure                                                 | web          |
    |        | GET|HEAD | home                 | home          | App\Http\Controllers\HomeController@index               | web,auth     |
    |        | GET|HEAD | login                | login         | App\Http\Controllers\Auth\LoginController@showLoginForm | web,guest    |
    |        | POST     | login                |               | App\Http\Controllers\Auth\LoginController@login         | web,guest    |
    |        | POST     | logout               | logout        | App\Http\Controllers\Auth\LoginController@logout        | web          |


  4. Next, alter your User model and corresponding migration. Introduce an ldap username column so you can keep track of which users have been previous authenticated to use the application. After making changes to your migration, don’t forget to re-run your user table migration:
    $php artisan migrate:refresh

    Here’s a sample from my migration file – as you can see the changes required are minimal. My ldap identifier is ’ladap_username’:

         * Run the migrations.
         * @return void
        public function up()
            Schema::create('users', function (Blueprint $table) {
                $table->string('ldap_username')->unique( );


  5. Use composer to install Adldap2. Edit the “require” block of your composer.json file:
        "require": {
            "php": ">=7.0.0",
            "fideloper/proxy": "~3.3",
            "laravel/framework": "5.5.*",
            "laravel/tinker": "~1.0",
            "adldap2/adldap2-laravel": "^3.0",

    Then update composer and refresh the autoloader:

    $composer update
    $composer dump-autoload


  6. Configure your LDAP settings. Following is a list of the available config options with examples and short description of each:
    #LDAP user account query string fragment that precedes your 'username' value
    #LDAP user account query string fragment that follows your 'username' value
    #LDAP directory hostname(s)
    #LDAP distinguished name used as the basis for your user account queries
    #If your LDAP instance requires your app to authenticate, provide the
    #relevant username and password in these fields

    There are a few other options that can be configured but these are the typical minimum. These values are stored in ./config/adldap.php and ./config/adldap_auth.php, but you will want to set them in your .env file rather than editing directly.

  7. Customise your LoginController’s username to correspond with your Adldap2 settings. The LoginController uses an ‘email’ attribute by default but you might want to change this value to match your LDAP instance. This method is provided by the Illuminate\Foundation\Auth\AuthenticatesUsers trait.

         * We're doing LDAP Auth in this application
         * so use the ldap username instead of email address to login
         * This property corresponds with ‘ldap_username’ column in the user table
        public function username( ) {
            return ‘ldap_username’;


  8. Customise the login view field name. By default, the Laravel auth scaffold provides an email address username field. If your LDAP instance is set up to. use non-email usernames, you can avoid triggering the email field validator by changing the type from “email” to “username”.
    <input id="uid" type="username" class="form-control" name="uid" value="{{ old('uid') }}" autofocus>

By this stage you should hopefully have a successful LDAP integration and managing to authenticate users against it. The use-case covered in this tutorial relatively simple and there a stack of other advanced integrations that ADLDAP can support. If there’s a enough interest, I’ll consider working on a full user binding tutorial in the future.

Parting tips

  • LDAP implementations tend to vary greatly and don’t always follow standard conventions and structure. You should consult with the directory administrator and don’t make assumptions on how data is organised.
  • Spend a bit of time investigating the ldapsearch CLI tool. Testing your ldap base parameter and other queries in ldapsearch will be much faster than trying to work things out on-the-fly while developing your app. This will help you establish a point-of-failure boundary if you run into problems and can also assist in designing appropriate tests for application.
  • Consider in advance which model attributes you intend to read from LDAP and which you’ll store locally within your application. Reading data regularly from the directory will introduce a performance overhead cost, so caching data might be a sensible tactic in this case. Of course, caching can introduce performance and complexity issues of a different nature, so consider your approach carefully.

Leave a Reply

Your email address will not be published. Required fields are marked *