Maturity
LDAP and Active Directory support is partial. What works: storing one connection per organisation, testing it, and syncing the directory's groups into Govern's directory groups, by hand or on a schedule. What does not: LDAP is not a sign-in method. The connections that sign people in to Govern are SAML, OpenID Connect and social; use SAML or OIDC for single sign-on, and SCIM for provisioning.
Configure the connection
The console page is Identity Center > LDAP directory sync. Through the API:
curl -sS -X PUT "$KEYSTONE_URL/api/v1/organizations/$ORG_ID/ldap" \
-H "Authorization: Bearer $ADMIN_TOKEN" -H 'Content-Type: application/json' \
-d '{
"host": "ldap.corp.example.com",
"port": 636,
"use_tls": true,
"bind_dn": "cn=admin,dc=example,dc=com",
"bind_password": "secret",
"base_dn": "dc=example,dc=com",
"user_filter": "(uid={{.Username}})",
"group_mappings": { "cn=admins": "admin", "cn=users": "member" }
}'
- LDAP, LDAPS and StartTLS are supported.
- The bind password is encrypted with AES-256-GCM and never returned.
GETanswersbind_password_setinstead, and an emptybind_passwordonPUTkeeps the stored one. - TLS certificate verification is on by default. Skipping it is refused outside development.
Test and sync
| Route | Permission | Purpose |
|---|---|---|
GET /api/v1/organizations/{id}/ldap | ldap:read | The connection, without its password, and last_sync |
PUT /api/v1/organizations/{id}/ldap | ldap:update | Configure the connection |
POST /api/v1/organizations/{id}/ldap/test | ldap:create | Test connectivity and the service account bind |
POST /api/v1/organizations/{id}/ldap/sync | ldap:create | Sync the directory's groups into Govern now |
last_sync reports how the last manual or scheduled sync ended:
{
"last_sync": {
"at": "2026-10-10T09:00:00Z",
"status": "failed",
"message": "The directory server refused the bind DN and password.",
"last_succeeded_at": "2026-10-09T09:00:00Z",
"groups_created": 2,
"groups_updated": 1,
"groups_deleted": 0,
"members": 14
}
}
status is succeeded or failed. message is Govern's own wording of a failure, never the directory server's error text. After a failure, the counts and last_succeeded_at are those of the last success.