Self-hosted service
go-ldap/ldap avatar
go-ldap/ldap

go-ldap/ldap: LDAP v3 client operations for Go applications

Basic LDAP v3 functionality for the GO programming language.

2,458 stars390 forksGoNOASSERTION

At a glance

What is it?
go-ldap/ldap is a Go client library that implements LDAP v3 operations, from bind and search to password modify and content synchronization. It is for Go developers wiring authentication and directory lookups into a service, not for building a directory server.
Who is it for?
Adopt go-ldap/ldap when a Go service needs to bind against an existing directory or run searches, paging, and password modify operations, and when you can test against a real server using the Makefile's local OpenLDAP container. Do not adopt it to build a directory server, and do not expect the README to cover connection pooling or retry behavior, because it does not.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository last received commits 3 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 1, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What go-ldap/ldap solves for Go services that talk to a directory

Go's standard library has no LDAP client. A service that authenticates users against OpenLDAP or Active Directory has to speak the wire protocol itself: BER encoding, message IDs, bind state, and the search result stream. go-ldap/ldap is the package that does that work. The README describes it as "Basic LDAP v3 functionality for the GO programming language" and lists the specifications it implements, starting with RFC 4511 for basic operations.

The audience is narrow and specific: Go developers who already have a directory server and need a client. The library covers bind (simple, GSSAPI, SASL), search (normal, paging, asynchronous), add, modify, delete, modify DN, unbind, password modify, content synchronization, filter compile and decompile, server side sorting, extended operations, and controls. That list maps directly onto the operations an identity-aware backend performs. If your problem is "the user typed a password and I need to check it against the corporate directory," this package is the layer between your handler and the server.

How the library maps LDAP operations onto Go calls

The design follows the protocol rather than hiding it. The README states that the library implements RFC 4511 for basic operations and RFC 4514 for distinguished names parsing, so the API surface is organized around request and response pairs: Bind Requests / Responses, Search Requests / Responses, Modify Requests / Responses, and so on. A caller dials a connection, binds, issues an operation, and reads the result.

Two details in the README matter for architecture. First, connections support "non-TLS, TLS, STARTTLS, through a custom dialer." The custom dialer option is what lets a service route LDAP traffic through its own transport, for example a dialer that enforces timeouts or proxies through a sidecar. Second, search supports "normal, paging and asynchronous" modes. Paging matters because directories cap the number of entries a single search returns, and asynchronous search changes the consumption model from one blocking call to a stream of results. Filter compile and decompile is the other piece worth noting: it means the library can turn a filter string into a structure and back, which is useful when filters are generated rather than written by hand.

The repository layout reinforces that the library is the whole product. The top level holds .github/, CONTRIBUTING.md, LICENSE, Makefile, README.md, SECURITY.md, testdata/, and v3/. The Makefile states plainly: "The module lives in v3/; the repository root holds no go.mod." There is no server component. Everything under testdata/ exists to feed the test container, not to ship a directory.

Installing go-ldap/ldap and running a first bind and search

The README gives one installation line, under the heading Go Modules:

bash
go get github.com/go-ldap/ldap/v3

The module path carries the v3 major version, so imports use the same suffix. The connection options in the README include non-TLS, TLS, and STARTTLS, and the local test server is reachable at `ldap://127.0.0.1:389`.

After connecting and binding, a search request returns entries. The README lists Search Requests / Responses as a feature, including paging and asynchronous variants; the basic synchronous call is the starting point. The exact call signature is not shown in the README, so read the package documentation linked at the top of the README before writing the search, and check the test files under `v3/` for working examples.

If you want a directory to test against, the repository's Makefile provides one. It requires docker or podman in PATH and errors out if neither is found. The target is `make local-server`, which runs `docker.io/osixia/openldap:1.5.0` with `LDAP_ADMIN_PASSWORD` set to `admin123`, publishes `127.0.0.1:3389:389` and `127.0.0.1:3636:636`, waits until `ldapsearch` succeeds against `ldap://127.0.0.1:389`, then loads the LDIF files from `testdata/`.

bash
make local-server
cd ./v3
make -f ../Makefile
make stop-local-server

Note the port mapping: the container's 389 is published on host port 3389, so a client on the host points at `ldap://127.0.0.1:3389`, while the readiness check inside the container uses `ldap://127.0.0.1:389`. Getting that wrong produces a connection refused error that looks like a server problem.

Where go-ldap/ldap is the wrong choice

The clearest limit is in the name and the README: this is a client. If you need to run a directory, this repository will not help. The Makefile pulls `docker.io/osixia/openldap:1.5.0` for testing precisely because the project has no server of its own.

The second limit is documentation depth. The README is a feature list and an install line. It does not document connection pooling, retry policy, or how a connection behaves after a server restart or an idle timeout. Those are the questions that decide whether a long-running service is stable, and the README is silent on all of them. A reader has to go to the package documentation on godoc, which the README links at the top, or read the source.

The third is protocol coverage versus server reality. The README lists RFC 4533 content synchronization, RFC 2891 server side sorting, and the draft for tree delete. Exposing a control in a client library does not mean the server you connect to supports it. Active Directory and OpenLDAP differ here, and an operation that works in the local test container may fail against production. Treat the RFC list as client capability, not as a compatibility guarantee.

How go-ldap/ldap differs from a general purpose LDAP client

The obvious comparison is the `ldapsearch` and `ldapmodify` command line tools from the OpenLDAP suite, which the project's own Makefile uses for its readiness check and for the anonymous access modification. Those tools are the right answer for one-off inspection and for scripts. The difference in approach is that they are processes with text output, while go-ldap/ldap is a library that returns Go structs inside your program's control flow. If your service needs to bind a user during an HTTP request and branch on the result, shelling out to `ldapsearch` is worse on every axis: process spawn cost, parsing, and error handling.

A closer comparison is a higher-level identity abstraction, such as a package that wraps several directory backends behind one interface. go-ldap/ldap deliberately does not do that. It stays at the protocol layer, which is why the README can enumerate RFC numbers instead of describing a user model. The trade-off is real: you get control over filters, scopes, controls, and paging, and you take on the responsibility for connection lifecycle and error interpretation that a higher-level wrapper would absorb. For a team that only needs "does this username and password work," that is more protocol than the task requires. For a team that needs paged searches with server side sorting against a specific directory, the lower layer is the point.

Maintenance, upgrade cost, and the licence question

The repository is not archived, and the last push was on 2026-09-25, three days before this writing. Releases are frequent: v3.4.12 on 2025-10-01, v3.4.13 on 2026-03-17, and v3.4.14 on 2026-07-16. The version numbers stay inside v3, so upgrades within the line are patch-level by semver convention, though the README does not publish a compatibility policy and you should not assume one.

Upgrade cost is mostly the module path. Because the module lives in `v3/` and the import path ends in `/v3`, a future v4 would be a new import path and a mechanical but repository-wide change. The Makefile also shows the maintenance workflow: `make` at the default target runs fmt, vet, lint, build, and test, and the local-server target requires a container runtime. Anyone contributing or reproducing a bug needs docker or podman installed, since the Makefile errors out without one.

On licensing, the repository's LICENSE file is present at the top level, but the metadata reports the licence as NOASSERTION, meaning the automated classifier could not match it to a known SPDX identifier. That is a signal to open the LICENSE file and read it before shipping the dependency in a commercial product. This is not legal advice; it is a reason to have someone read the actual text rather than trusting a badge.

Editorial conclusion

Adopt go-ldap/ldap when a Go service needs to bind against an existing directory or run searches, paging, and password modify operations, and when you can test against a real server using the Makefile's local OpenLDAP container. Do not adopt it to build a directory server, and do not expect the README to cover connection pooling or retry behavior, because it does not. Before you commit, verify which RFCs your target server actually implements, particularly RFC 4533 content synchronization and RFC 2891 server side sorting, since the library exposes them but the server decides whether they work.

Frequently asked questions

Is LDAP still used today, and does go-ldap/ldap depend on it?

go-ldap/ldap is a client for LDAP v3 directories, so its usefulness tracks whether the directory you integrate with still speaks LDAP. The library implements RFC 4511 for basic operations and several related RFCs, which means it targets deployed directory servers rather than a new protocol.

What is LDAP and why is it used, in the context of this Go library?

The README describes the project as basic LDAP v3 functionality for Go and lists operations such as bind, search, add, modify, delete, and password modify. In practice the library is used by a Go program that needs to authenticate against or query an existing directory server.

Is LDAP a security risk when used through go-ldap/ldap?

The README lists non-TLS, TLS, and STARTTLS connection options, so the transport is a choice the caller makes rather than a default the library imposes. The README does not discuss credential handling or recommend one transport over another, so the security posture depends on how you configure the connection.

Am I using LDAP or LDAPS with go-ldap/ldap?

The README distinguishes non-TLS, TLS, and STARTTLS connections, and the local test server maps port 636 in addition to 389, with the Makefile publishing 127.0.0.1:3636:636. Which one your code uses depends on the URL you pass to the dial call, not on a library default.

Official sources

  1. go-ldap/ldap on GitHub
  2. Issues
  3. README
  4. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/go-ldap-ldap.svg)](https://hysenlabs.com/projects/go-ldap-ldap)