directorytree/ldaprecord-laravel
LdapRecord-Laravel integrates LDAP, OpenLDAP, and Active Directory with Laravel using Eloquent-style models, native authentication, user synchronization, multi-domain connections, and a testing toolkit, making it simpler to build applications that securely read and manage directory data.
Architecture fit
This is a Laravel-native package, not a sidecar, proxy, or hosted service — which is the single most important architectural fact for scoping. It plugs into three seams the framework already owns: an auth guard/provider pair for login, an Eloquent-shaped ActiveRecord model layer for directory entries, and Artisan commands plus a scheduler hook for batch synchronization. There is no new runtime component to deploy, no new network hop in the request path beyond the LDAP bind itself, and no new data store to operate — the optional import path writes into your existing database.
Fit is high only if the host application is already Laravel and the team works in Laravel idioms. The package's leverage is entirely "your team already knows this shape." In a Symfony, Rails, or polyglot codebase, that leverage evaporates and you are paying for an abstraction you cannot reuse.
The one real architectural asymmetry: authentication is synchronous and in-request (bind against the directory on every login), while provisioning is asynchronous and batched. Those two have completely different latency, failure, and blast-radius profiles and should be planned, flagged, and rolled out as two separate capabilities rather than one "LDAP integration."
Integration feasibility
Mechanically low. composer require, publish config, define one or more connections, wire the guard and user provider, point a model at your directory object classes. The code footprint is small — days, not weeks, for a Laravel-fluent engineer with a working directory to test against.
The real cost is not code, it is coordination, and it sits outside your org:
ext-ldap compiled and enabled across every app container and CI image. Trivial to state, routinely missed in Docker baselines.The Directory Emulator materially improves feasibility. Local development, CI, and a credible demo environment all work without a live customer directory — which removes the classic "we can only validate against the customer's AD in staging" bottleneck where these projects blow their estimates. Treat the emulator as a scheduling asset, not a testing nicety: it is what lets you start before the customer delivers credentials. But it is an emulator, and the gap between emulator-green and real-directory-green is the residual risk you are accepting.
Technical risk
memberof semantics, attribute casing, binary attributes. The emulator covers a lot (recent fixes address memberof emulation, custom connections, orWhereNotHas behavior) but it will not cover your customer's specific schema oddity. Budget a discovery window against a real directory.RulePassed/RuleFailed authentication events exist since v3.2.0. None of this is on by default in a way that satisfies an audit requirement — it is a deliberate configuration task.Key questions to answer before committing engineering time
Stack fit
Laravel 10 through 13, PHP with ext-ldap, and a relational database if you take the import path. Two schema details worth flagging: SQL Server unique-index support was addressed in v2.7.1, and the --delete-missing soft-delete path respects the Eloquent model's deleted_at date format since v3.4.1 — both matter if you are not on stock MySQL. Queue workers (Horizon or equivalent) are the natural home for scheduled imports. Logging should be routed through an explicit named channel rather than the default stack.
Migration path
Do not frame this as an auth rewrite. The LDAP guard coexists with the existing database guard; the correct shape is an additive guard plus a per-tenant flag, with everyone else untouched on password auth. Three reversible steps:
ldap:browse to prove connectivity, bind, base DN, and OU scope against the real directory. No user-facing change. This step is where you discover the schema quirks.ldap:import as a scheduled job with importer query scopes to bound the scope, and reconcile into the existing users table. Handle the password_column => false case deliberately — v3.3.2 specifically fixed rehash behavior when password storage is disabled, which is exactly the directory-only-auth configuration you will want.Compatibility
Pin the package constraint and the matching LdapRecord core version together — v3.0.4 exists because that coupling was previously loose, and there is no reason to relearn it. Verify the emulator version you develop against matches the line you run in production. Confirm the PHP version and ext-ldap build in every environment, including CI, before the first sprint rather than during it.
Sequencing
Four independently shippable slices, each valuable alone and none blocking the next:
--delete-missing deprovisioning. Arguably the more defensible value story — it converts a manual onboarding ritual into a job and simultaneously closes the stale-account finding that appears in most SOC 2 and GDPR reviews.Gate each tranche on pipeline rather than committing the entire "enterprise readiness" tier up front. Slices 1 and 2 are commonly co-sold; 3 and 4 frequently never get funded, and that is fine.
Maintenance
Internal ownership is the honest answer. The package is actively maintained — v4.0 followed by v4.0.1 through v4.0.5 within a short window, each a narrow, credible patch (logging channel adherence, LDAP error-code parsing, password-mutator attribute detection, a float type hint, emulator chunk and connection handling) — but "actively maintained by a small group" and "maintained on your schedule" are different things. Commit to: pinned versions, a changelog watch, a scheduled upgrade slot per Laravel major, and a standing assumption that a breaking upgrade will arrive roughly once per framework cycle. The dependency surface is small, which caps the work, but you also depend transitively on LdapRecord core, so track both.
Support
Community only. No SLA, no indemnity, no named contact, no escalation path. For an internal-tool or B2B integration this is usually acceptable; for anything a customer's security review will inspect as an authentication control, it must be an explicit, recorded decision. Mitigate with an internal named owner, a runbook, and — because the guard is swappable — a realistic exit plan. The exit plan is the actual risk control here; write it down before you need it.
Scaling
Authentication cost is per-login and dominated by network round-trip to the domain controller, not by your application. Latency to an on-prem DC across a VPN can be tens to hundreds of milliseconds; that is invisible at low login volume and noticeable under burst or at peak-hour sign-in. Consider caching or a short-lived session assumption rather than binding on every user action.
Import cost is a full or scoped directory scan, chunked. The v4.0.5 chunk fixes (respecting chunk sizes, preserving emulator connections across isolated chunks) suggest chunking is an actively exercised path and worth load-testing at your actual directory size rather than trusting defaults. Volume guidance from the package's own positioning holds: hundreds to low tens of thousands of users on a scheduled cadence is the design center. Above ~100K users with a real-time freshness requirement, scheduled imports will not meet the target and this is the wrong tool.
Failure modes to design against
--delete-missing overreach. A bad base DN, an OU scope change on the customer side, or a partial directory read can cause the job to mark real, active users as departed. This is the highest-consequence failure in the entire integration. Mitigate with importer query scopes, a dry-run mode, a soft-delete window before hard deletion, and a count-anomaly alert on how many records a run proposes to remove.Ramp-up
A Laravel-fluent engineer is productive in this package within days; the API is intentionally Eloquent-shaped and the documentation at ldaprecord.com is the primary reference, including the v3 and v4 upgrade guides. The slow part is not the package, it is LDAP domain literacy: what a base DN actually scopes, how binds differ from searches, why nested groups behave the way they do, and what an error code means on this particular customer's directory implementation. Plan for that knowledge to be acquired during the pilot tenant, and make sure at least one person owns it afterward — otherwise the integration is one departure away from unmaintained.
Use the Directory Emulator as the ramp-up vehicle: it lets a new engineer build and test against LDAP-shaped behavior without waiting on customer credentials, and it doubles as the demo environment before a design-partner tenant exists.
How can I help you explore Laravel packages today?