Active Directory / LDAP Integration for Corporate Mobile Application
Direct LDAP integration in mobile app — almost always architectural mistake. Mobile client shouldn't connect to LDAP directly: ports 389/636 closed behind corporate firewall, LDAP-bind credentials can't be stored on device, connection through mobile internet to on-premise AD — unstable. Right schema: mobile → backend API → AD/LDAP.
Integration Architecture
Backend acts as LDAP proxy: accepts requests from mobile via HTTPS with JWT authorization, queries AD/LDAP inside corporate network, returns data in REST format.
Mobile ──HTTPS/JWT──► Backend API ──LDAP 636──► Active Directory
└──LDAP 389──► OpenLDAP
For authentication via AD on backend use LDAP-bind:
// Node.js, ldapjs
const client = ldap.createClient({
url: "ldaps://dc01.company.local:636",
tlsOptions: { rejectUnauthorized: true, ca: [fs.readFileSync("ca.crt")] },
});
async function authenticateUser(username, password) {
const userDN = `cn=${username},ou=Users,dc=company,dc=local`;
return new Promise((resolve, reject) => {
client.bind(userDN, password, (err) => {
if (err) {
reject(new InvalidCredentialsError());
} else {
resolve(true);
client.unbind();
}
});
});
}
After successful bind, backend generates JWT and returns to mobile. User password never leaves backend.
Getting User Attributes
AD stores rich attributes: displayName, mail, telephoneNumber, department, manager, memberOf (groups), thumbnailPhoto (avatar). For corporate app this is valuable data source — no need to duplicate user profiles.
async function getUserAttributes(username) {
const base = "ou=Users,dc=company,dc=local";
const opts = {
filter: `(sAMAccountName=${username})`,
scope: "sub",
attributes: [
"displayName",
"mail",
"department",
"manager",
"memberOf",
"thumbnailPhoto",
],
};
return new Promise((resolve, reject) => {
client.search(base, opts, (err, res) => {
let entry = null;
res.on("searchEntry", (e) => (entry = e.object));
res.on("end", () => resolve(entry));
res.on("error", reject);
});
});
}
thumbnailPhoto — JPEG in base64 directly in AD. Return as base64 string or save to object storage and return URL.
memberOf contains DN of groups: CN=VPN-Users,OU=Groups,DC=company,DC=local. Groups determine user rights in app — parse CN from DN and map to application roles.
Working with Organization Structure
AD contains hierarchy via manager attribute (DN of manager) and directReports. Build org tree via recursive LDAP queries — possible but slow on deep hierarchies. Better: cache structure on backend with periodic updates (every hour/day), mobile requests ready graph.
// Android — org structure display
data class OrgNode(
val employeeId: String,
val name: String,
val position: String,
val department: String,
val avatarUrl: String?,
val directReports: List<OrgNode>
)
@Composable
fun OrgChart(rootNode: OrgNode) {
LazyColumn {
item { EmployeeCard(node = rootNode, level = 0) }
items(rootNode.directReports) { report ->
EmployeeCard(node = report, level = 1)
// Recursively for nested levels via expandable state
}
}
}
Employee Search
Full-text search via AD via LDAP filter:
const filter = `(&(objectClass=person)(|(displayName=*${query}*)(mail=*${query}*)(sAMAccountName=*${query}*)))`;
Performance: wildcard at start (*${query}*) doesn't use AD index, slow search on large base. For apps with thousands of employees — sync AD to Elasticsearch or PostgreSQL full-text search, search there.
Synchronization and Cache
AD — source of truth for employee data. Mobile app works with backend cache. For actuality: webhook events via AD Event Log (if AD 2016+) or polling every 15–30 minutes for changes via uSNChanged attribute.
On employee termination, AD account deactivated. Backend on next refresh_token sees failed LDAP lookup and invalidates JWT. Mobile redirected to login.
Azure AD (Entra ID) Specifics
If company uses Azure AD (Microsoft Entra ID) — no direct LDAP, only Microsoft Graph API or OIDC. Graph API much more convenient: REST, JSON, rich documentation. GET /users/{id}?$select=displayName,mail,department,manager,memberOf returns everything same as LDAP, but without AD libraries.
For hybrid environment (on-premise AD + Azure AD with Azure AD Connect) — data synced, can use either Graph API or on-premise LDAP depending on security requirements.
AD/LDAP integration (backend proxy + mobile client + org structure + search): 3–6 weeks. Cost estimated individually after analyzing customer infrastructure.







