Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Adldap2 Laravel Laravel Package

adldap2/adldap2-laravel

Adldap2 Laravel integrates the Adldap2 LDAP library with Laravel, providing authentication plus user and group management through a config-driven API. Use it to connect Laravel applications to Active Directory and OpenLDAP servers for directory queries, search, and login.

View on GitHub
Deep Wiki
Context7

Getting Started

Before you install, know what you're adopting. Adldap2-Laravel is archived. The final tag is v6.1.7, and the only thing it added over v6.1.6 was Laravel 10.x compatibility. That makes Laravel 10 the hard ceiling: there is no support for Laravel 11+, no PHP 8.2+/8.3+ deprecation fixes, and no security patches coming. Treat v6.1.7 as a frozen artifact, not a maintained dependency. If you're starting greenfield, directorytree/ldaprecord-laravel is the author's successor and a near drop-in conceptually. Use Adldap2-Laravel when you're inheriting an app that already depends on it, not when you're choosing.

Minimal install, pinned to the last tag:

composer require adldap2/adldap2-laravel:6.1.7
php artisan vendor:publish --provider="Adldap\Laravel\AdldapServiceProvider"

That publishes config/ldap.php. Fill in the connections.default.settings block — hosts, base_dn, username, password, port, use_ssl/use_tls, timeout, and account_suffix/account_prefix if your directory expects user@domain or DOMAIN\user rather than a bare sAMAccountName. Keep auto_connect false so the connection stays lazy.

Wire up auth in config/auth.php:

'providers' => [
    'users' => [
        'driver' => 'ldap',
        'model'  => App\Models\User::class,
    ],
],

Then add the trait to your user model so you can reach into the directory from an authenticated request:

use Adldap\Laravel\Traits\HasLdapUser;

class User extends Authenticatable
{
    use HasLdapUser;
}

First thing to verify — and you should do this before touching auth at all — is that the connection and bind actually work:

php artisan tinker
>>> Adldap::search()->users()->first();

If that returns an entry, the plumbing is fine and any remaining failure is configuration of identifiers/sync. If it throws, you're debugging network, bind credentials, or base DN — not Laravel. That single check saves hours.

The canonical first use case: an AD user logs in with their domain credentials, no local password exists, and the package creates an Eloquent row on first successful bind. That's the default behavior once the provider is switched; login.ldap / login.database (or the identifiers block on v6+) controls which backends are tried.

If you're on Laravel 10, install v6.1.7 specifically rather than floating a constraint — it's the only tag that declares L10 support, and it's the last one you'll ever get. If you're on Laravel 11+, the package will not work; the migration to LdapRecord-Laravel is now a prerequisite, not a nice-to-have.

Implementation Patterns

LDAP auth with a local user mirror (the 90% case). The provider binds against LDAP, then creates/updates the Eloquent record using sync_attributes, a map of Eloquent column → LDAP attribute:

'sync_attributes' => [
    'name'  => 'cn',
    'email' => 'userprincipalname',
    'title' => 'title',
],

'sync_existing' => [
    'email' => 'mail',  // only overwrite email from LDAP if currently null
],

Keep a stable identifier in the mapping (GUID, or the DN) and index it in the database; you'll need it for HasLdapUser to resolve $user->ldap later, and for bulk sync to match rows.

Bulk import / seeding. php artisan adldap:import pulls directory users into the database without requiring them to log in first — useful for pre-provisioning, for populating a people directory, and for backfilling a local app before you flip the auth driver. Pair it with --filter to scope by OU or group, and run it on a schedule if the directory is the source of truth.

Reading live directory data. With the trait, $user->ldap returns the Adldap\Models\User for the current request. Use the facade for anything more open-ended:

$results = Adldap::search()->users()
    ->where('department', '=', 'Engineering')
    ->where('mail', 'ends_with', '@example.com')
    ->get();

$group = Adldap::search()->groups()->find('CN=VPN Users,OU=Groups,DC=example,DC=com');
$members = $group->getMembers();

Authorization from group membership. Listen to the package's authentication/sync events and map AD groups to local roles rather than querying LDAP in middleware on every request:

Event::listen(\Adldap\Laravel\Events\Authenticated::class, function ($event) {
    $groups = $event->user->getGroups()->pluck('cn')->all();
    $event->model->syncRoles($groups);
});

This keeps the role check cheap and gives you an offline story if the DC is unreachable.

Windows SSO. Adldap\Laravel\Middleware\WindowsAuthenticate trusts the REMOTE_USER/AUTH_USER server variable from IIS (or a reverse proxy that sets it) and logs the user in without a password prompt. Only use it behind a proxy you control — the header is trivially spoofable if exposed directly.

Directory writes. It's not read-only — $ldapUser->setAttribute('telephoneNumber', $phone)->save() and $ldapUser->addGroup($group) work. Use this for profile self-service rather than giving the app a read-only bind account; keep the write account separate and narrowly scoped.

Multiple directories. Define additional connections and reach them with Adldap::connection('contractors'). Common in M&A situations or when a trusted domain lives in another forest.

Testing. The provider will happily try to open a socket from a test. Either stub the facade (Adldap::shouldReceive('search')...) or, better, run feature tests with the plain Eloquent user provider and cover LDAP-specific logic against mocked models. Don't let CI depend on a reachable DC.

Gotchas and Tips

The archive is the headline, and v6.1.7 proves the pattern. The last commit of substance was a Laravel 10 compat PR — a maintenance bump, not a feature. Nothing has landed since, and nothing will. If you must stay, pin 6.1.7 exactly, fence the dependency behind an interface, and plan a migration to LdapRecord-Laravel — the config shape and trait API are close enough that the move is mechanical rather than a rewrite.

Don't read v6.1.7 as "actively supported on Laravel 10." It means the package installs and runs on L10; the L10 support burden (deprecations, PHP 8.2/8.3 warnings, framework deprecation notices that become exceptions in strict error handling) is entirely yours. Expect to silence or patch deprecation noise yourself.

auto_connect should essentially always be false. With it on, every queued command and health check opens and authenticates a connection. You get slow boots and cascading failures when the DC is down.

AD caps unbounded searches at 1000 entries. ->get() on a large tree silently returns a truncated set. Use the paginated search API and process in chunks for any import or reporting job. Also remember memberOf in AD does not include nested groups — you need the 1.2.840.113556.1.4.1941 matching rule or a recursive walk, or your role mapping will quietly miss inherited access.

Unencrypted connections can't change passwords. AD rejects unicodePwd and password-set operations over plain 389. Use LDAPS on 636 (or StartTLS) with a trusted CA for any password feature, including "change password on first login."

Attribute names are case-insensitive on the wire but the schema normalizes them. getAttribute('mail') returns an array of values; getFirstAttribute('mail') returns the scalar. Multi-valued attributes (proxyAddresses, memberOf) will bite you if you expect a string.

config:cache freezes your directory credentials. Put all connection values in env() inside the published config rather than editing literals, and never call env() outside config files. A stale cached bind password after a rotation is one of the more confusing failures you'll debug.

Special characters in bind passwords need quoting in .env. A password with # or $ silently truncates and you get "invalid credentials" that look like a server problem.

Referrals. Multi-domain forests return referrals; without follow_referrals enabled, searches for users in other domains come back empty rather than erroring.

Auth identifier mismatch is the classic support ticket. If your login form field is username but your LDAP identifiers list only mail, users with a sAMAccountName that isn't their email can't log in. Set the identifiers list to include every form the directory accepts, in order.

Set the timeout, and set it low. A default PHP socket timeout means a dead DC stalls a login for 60+ seconds. timeout => 3 with a friendly "directory unavailable" message beats a hung request worker.

Sync runs on create/update at login, not on directory change. If an employee's title changes in AD, it propagates the next time they log in — or whenever you next run the import command. Don't build features that assume real-time coherence.

Extension points worth knowing: custom schemas (Adldap\Schemas\OpenLDAP vs ActiveDirectory) if you're not on AD, custom connection classes if you need unusual TLS handling, and the package's events as the seam for anything cross-cutting. Overriding the user provider is possible but rarely worth it — the event hooks cover most needs. Given the archive, prefer forking over subclassing: a vendored copy you control is more honest than an extension point on a dead package.

Log hygiene. Bind credentials and full DNs end up in exception traces regularly. Scrub them before anything reaches an error tracker.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
mehedimi/laravel-amp-mail
happones/laravel-vue-i18n-generator
jwerd/inertia-table
siberfx/flysystem-wasabi
hollyit/token-replace
ippanelcom/laravel-sdk
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel