Active Directory Authentication
This feature is part of Countly Enterprise. To get access, contact sales or compare versions. Existing customers can reach the support portal with questions.
Overview
The Active Directory feature enables Countly Enterprise to integrate with both Microsoft Azure Active Directory (Azure AD) and on-premises Active Directory (LDAP). This unified authentication solution allows organizations to leverage existing directory infrastructure for centralized user management and role-based access control.
The feature supports two authentication modes:
- Azure AD (Cloud): OAuth2-based authentication with Azure Active Directory
- LDAP (On-premises): Direct LDAP authentication with on-premises Active Directory or compatible LDAP servers
Both modes support automatic user group mapping to Countly administrative roles, enabling zero-touch provisioning and enterprise-grade access control.
Key Features
- Dual Authentication Modes: Support for both Azure AD and on-premises LDAP
- Group-based Role Mapping: Automatic assignment of Countly roles based on AD group membership
- Per-App Group Configuration: Different AD group requirements per application
- Tenant Configuration: Azure AD supports multi-tenant (
multi) or tenant-specific configuration - Permission Groups: Default permission groups for all authenticated users
- Push Approver Mapping: Specific AD groups mapped to push approver permission
- TLS/SSL Support: Secure LDAP connections with certificate validation
- Retry Logic: Configurable connection retry attempts for reliability
- Azure AD OAuth2: Standards-compliant OAuth2 flow for cloud deployments
Architecture
Azure AD Flow
User Login → Azure AD OAuth2 → Exchange code for access token
→ Fetch profile (/me) + groups (/me/memberOf)
→ Map to Countly Roles → Create/Update Session
LDAP Flow
User Credentials → LDAP Bind → Query User Groups → Map to Countly Roles
→ Create/Update Session
Configuration Settings
Azure AD Configuration
Connection Settings
| Setting | Default | Type | Description | Environment Variable |
|---|---|---|---|---|
clientId | '8db7e011-a15f-4454-9472-2f475550c7a7' | String | Azure AD application client ID | COUNTLY_CONFIG_PLUGINAD_CLIENTID |
clientSecret | 'c33wTBoBv@_1jPm.e1ENTLhpoB]IE@iC' | String | Azure AD application client secret | COUNTLY_CONFIG_PLUGINAD_CLIENTSECRET |
tenant | 'multi' | String | Tenant value (multi or a specific tenant ID) | COUNTLY_CONFIG_PLUGINAD_TENANT |
Role Mapping Settings
| Setting | Default | Type | Description | Environment Variable |
|---|---|---|---|---|
globalAdminGroup | 'countly-global-admins' | String | Azure AD group that becomes Countly global admin | COUNTLY_CONFIG_PLUGINAD_GLOBALADMINGROUP |
defaultGroup | 'default-group' | String | Countly default permission group for all users | COUNTLY_CONFIG_PLUGINAD_DEFAULTGROUP |
pushApproverGroups | ['push-approver-group'] | Array | Azure AD groups mapped to push approver permission | COUNTLY_CONFIG_PLUGINAD_PUSHAPPROVERGROUPS |
LDAP Configuration
Connection Settings
| Setting | Default | Type | Description | Environment Variable |
|---|---|---|---|---|
ldapURI | 'ldap://localhost:389' | String | LDAP server URI (use ldaps:// for TLS) | COUNTLY_CONFIG_PLUGINAD_LDAPURI |
baseDN | 'DC=active-directory,DC=count,DC=ly' | String | Base LDAP distinguished name for user search | COUNTLY_CONFIG_PLUGINAD_BASEDN |
domainPrefix | 'ACTIVE-DIRECTOR\\' | String | Domain prefix for usernames (e.g., 'ACME\') | COUNTLY_CONFIG_PLUGINAD_DOMAINPREFIX |
adminUsername | 'username' | String | Service account username for LDAP queries | COUNTLY_CONFIG_PLUGINAD_ADMINUSERNAME |
adminPassword | 'password' | String | Service account password (use countly encrypt for encryption) | COUNTLY_CONFIG_PLUGINAD_ADMINPASSWORD |
Authentication Settings
| Setting | Default | Type | Description | Environment Variable |
|---|---|---|---|---|
timeout | 20000 | Number | LDAP operation timeout (milliseconds) | COUNTLY_CONFIG_PLUGINAD_TIMEOUT |
retry | 5 | Number | Maximum LDAP connection retry attempts | COUNTLY_CONFIG_PLUGINAD_RETRY |
tlsEnabled | false | Boolean | Enable TLS for LDAP connections | COUNTLY_CONFIG_PLUGINAD_TLSENABLED |
tlsCert | '' | String | TLS certificate path for secure LDAP | COUNTLY_CONFIG_PLUGINAD_TLSCERT |
Role Mapping Settings
| Setting | Default | Type | Description | Environment Variable |
|---|---|---|---|---|
globalAdminGroup | 'ad-global-admin' | String | LDAP group that becomes Countly global admin | COUNTLY_CONFIG_PLUGINAD_GLOBALADMINGROUP |
defaultGroup | 'default' | String | Countly default permission group for all users | COUNTLY_CONFIG_PLUGINAD_DEFAULTGROUP |
pushApproverGroups | ['push-approver-group'] | Array | LDAP groups mapped to push approver permission | COUNTLY_CONFIG_PLUGINAD_PUSHAPPROVERGROUPS |
useCountlyGroups | true | Boolean | Use Countly group mapping (true) or legacy app-level AD group mapping (false) | COUNTLY_CONFIG_PLUGINAD_USECOUNTLYGROUPS |
Per-Application Group Configuration
When an application is created with AD group settings, the feature stores three group mappings in countly.apps:
| Field | Type | Description |
|---|---|---|
ad_group_admin | String | AD group for app administrators; app create hook appends -{app_name}-admin when suffix is not already detected |
ad_group_user | String | AD group for app users; app create hook appends -{app_name}-user when suffix is not already detected |
ad_group_marketing | String | AD group for app marketing users; app create hook appends -{app_name}-marketing when suffix is not already detected |
Configuration Methods
Method 1: Azure AD Configuration File
Create or edit config.js from config.azure.sample.js in the Active Directory feature directory:
const config = {
// Azure AD Connection
clientId: '8db7e011-a15f-4454-9472-2f475550c7a7',
clientSecret: 'c33wTBoBv@_1jPm.e1ENTLhpoB]IE@iC',
tenant: 'multi', // 'multi' for multi-tenant or a specific tenant ID
// Role Mapping
globalAdminGroup: 'countly-global-admins',
defaultGroup: 'default-group',
pushApproverGroups: ['push-approver-group'],
};
module.exports = require('../../api/configextender')('PLUGINAD', config, process.env, {
CLIENTID: 'clientId',
CLIENTSECRET: 'clientSecret',
GLOBALADMINGROUP: 'globalAdminGroup',
DEFAULTGROUP: 'defaultGroup',
PUSHAPPROVERGROUPS: 'pushApproverGroups',
TENANT: 'tenant'
});
How mode is selected: Azure AD mode is used when clientId and clientSecret are present in config.js.
Method 2: LDAP Configuration File
Create or edit config.js from config.ldap.sample.js in the Active Directory feature directory:
const config = {
// LDAP Connection
ldapURI: 'ldaps://ad.company.com:636',
baseDN: 'CN=Users,DC=company,DC=com',
domainPrefix: 'COMPANY\\',
adminUsername: 'ldap-reader',
adminPassword: 'encrypted-password-here',
// Connection Options
timeout: 20000,
retry: 5,
tlsEnabled: true,
tlsCert: '/etc/ssl/certs/ad.crt',
// Role Mapping
globalAdminGroup: 'ad-global-admin',
defaultGroup: 'default',
pushApproverGroups: ['push-approver-group'],
useCountlyGroups: true
};
module.exports = require('../../api/configextender')('PLUGINAD', config, process.env, {
LDAPURI: 'ldapURI',
BASEDN: 'baseDN',
DOMAINPREFIX: 'domainPrefix',
ADMINUSERNAME: 'adminUsername',
ADMINPASSWORD: 'adminPassword',
GLOBALADMINGROUP: 'globalAdminGroup',
DEFAULTGROUP: 'defaultGroup',
PUSHAPPROVERGROUPS: 'pushApproverGroups',
USECOUNTLYGROUPS: 'useCountlyGroups',
TIMEOUT: 'timeout',
RETRY: 'retry',
TLSENABLED: 'tlsEnabled',
TLSCERT: 'tlsCert'
});
How mode is selected: LDAP mode is used when clientId / clientSecret are not configured.
Method 3: Environment Variables
Set with prefix COUNTLY_CONFIG_PLUGINAD_:
# Azure AD
export COUNTLY_CONFIG_PLUGINAD_CLIENTID="8db7e011-..."
export COUNTLY_CONFIG_PLUGINAD_CLIENTSECRET="c33wTBoBv@..."
export COUNTLY_CONFIG_PLUGINAD_TENANT="multi"
export COUNTLY_CONFIG_PLUGINAD_GLOBALADMINGROUP="countly-global-admins"
export COUNTLY_CONFIG_PLUGINAD_DEFAULTGROUP="default-group"
export COUNTLY_CONFIG_PLUGINAD_PUSHAPPROVERGROUPS='["push-approver-group"]'
# LDAP
export COUNTLY_CONFIG_PLUGINAD_LDAPURI="ldaps://ad.company.com:636"
export COUNTLY_CONFIG_PLUGINAD_BASEDN="CN=Users,DC=company,DC=com"
export COUNTLY_CONFIG_PLUGINAD_DOMAINPREFIX="COMPANY\\"
export COUNTLY_CONFIG_PLUGINAD_ADMINUSERNAME="ldap-reader"
export COUNTLY_CONFIG_PLUGINAD_ADMINPASSWORD="encrypted-password"
export COUNTLY_CONFIG_PLUGINAD_USECOUNTLYGROUPS="true"
Use Cases
Use Case 1: Azure AD Cloud Authentication
Enable enterprise-wide authentication using Azure Active Directory:
{
clientId: 'your-azure-client-id',
clientSecret: 'your-client-secret',
tenant: 'multi',
globalAdminGroup: 'Countly-Admins',
defaultGroup: 'Countly-Users',
pushApproverGroups: ['Countly-Push-Team']
}
Result: Users authenticate via Azure AD OAuth2; group memberships determine Countly roles automatically.
Use Case 2: On-Premises LDAP Authentication
Authenticate users against existing on-premises Active Directory:
{
ldapURI: 'ldaps://ad.company.com:636',
baseDN: 'CN=Users,DC=company,DC=com',
domainPrefix: 'COMPANY\\',
adminUsername: 'service-account',
adminPassword: 'encrypted-password',
tlsEnabled: true,
tlsCert: '/etc/ssl/certs/ad.crt',
globalAdminGroup: 'AD-Admins',
defaultGroup: 'AD-Users',
pushApproverGroups: ['Push-Team']
}
Result: Users log in with domain credentials; automatic group-based role assignment.
Use Case 3: Per-Application Group Configuration
Configure different AD groups for different applications:
// During app creation:
{
name: 'Analytics Dashboard',
ad_group_admin: 'analytics-admins', // → becomes 'analytics-admins-Analytics Dashboard-admin'
ad_group_user: 'analytics-users', // → becomes 'analytics-users-Analytics Dashboard-user'
ad_group_marketing: 'marketing-team' // → becomes 'marketing-team-Analytics Dashboard-marketing'
}
Result: Different AD groups can have different permissions levels per application.
Use Case 4: Legacy Per-App AD Group Mapping
Use legacy app-level AD group mapping instead of Countly groups:
{
ldapURI: 'ldaps://ad.company.com:636',
baseDN: 'CN=Users,DC=company,DC=com',
adminUsername: 'service-account',
adminPassword: 'encrypted-password',
useCountlyGroups: false
}
Result: AD groups are matched against app fields (ad_group_admin, ad_group_user, ad_group_marketing) when assigning app-level roles.
Use Case 5: Multi-Tenant Azure AD
Support multiple Azure AD tenants in single Countly instance:
{
tenant: 'multi', // Allows any Azure AD tenant
clientId: 'shared-client-id',
clientSecret: 'shared-client-secret',
globalAdminGroup: 'countly-global-admins',
defaultGroup: 'countly-users'
}
Result: Users from any Azure AD tenant can authenticate; role assignment based on their tenant's group memberships.
Best Practices
Azure AD
- Use Multi-Tenant for SaaS: Set
tenant: 'multi'to allow any Azure AD organization - Secure Client Secret: Store client secret in secure configuration management, never in code
- Register Reply URLs: Ensure Azure app registration includes all Countly callback URLs
- Graph Permissions: Ensure Microsoft Graph permissions allow reading profile and group membership
- Test in Dev Tenant: Always test configuration in development Azure AD tenant first
LDAP (On-Premises)
- Use LDAPS: Always enable TLS in production (
tlsEnabled: true,ldaps://URI) - Dedicated Service Account: Create account with read-only permissions for LDAP queries
- Encrypt Password: Use
countly encryptto encryptadminPasswordin config - Certificate Validation: Provide valid certificate path for TLS validation
- Test Connectivity: Verify LDAP server is accessible before enabling in production
- Timeout Tuning: Increase timeout for WAN/cloud connections (30000-60000ms)
- Retry Logic: Adjust retry count based on network stability (default: 5)
General
- Group Testing: Verify group names exactly match AD configuration before enabling
- Role Mapping: Test role assignments for all group types (admin, user, approver)
- Backup Authentication: Maintain at least one local admin account for recovery
- Audit Logging: Monitor authentication logs for failed attempts and unusual patterns
- Regular Review: Periodically verify AD group memberships match intended access levels
Troubleshooting
Azure AD Authentication Failures
Problem: "Authentication failed" or "Invalid Azure AD credentials"
Solutions:
- Verify
clientIdandclientSecretmatch Azure AD application registration - Confirm redirect URIs in Azure AD app include all Countly URLs
- Check Azure AD tenant setting matches configuration (
multior specific tenant ID) - Verify user has necessary Azure AD group memberships
- Ensure Azure AD application has permission to read group memberships
Debug: Check Azure AD sign-in logs in Azure Portal
LDAP Authentication Failures
Problem: "LDAP bind failed" or "User not found"
Solutions:
- Test admin credentials with ldapsearch tool:
ldapsearch -D "CN=admin,DC=company,DC=com" -w password - Verify
baseDNis correct (use ldapsearch to discover correct DN) - Confirm
domainPrefixmatches actual domain structure - Check user exists in LDAP under configured
baseDN - Verify LDAP server allows search operations
Debug: Increase logging, check Countly error logs
Group Mapping Issues
Problem: Users authenticate but lack expected roles
Solutions:
- Verify group names exactly match
globalAdminGroup,defaultGroup,pushApproverGroups - Check user is member of groups in AD (use AD Users & Computers or Azure AD Portal)
- Confirm group names are case-sensitive in configuration
- Confirm matching values are aligned with Countly group names/group IDs (or legacy app-level AD group fields when
useCountlyGroups: false) - Verify
useCountlyGroupssetting matches your AD structure
Certificate/TLS Errors
Problem: "Certificate verification failed" or TLS connection errors
Solutions (LDAP only):
- Verify certificate file path is correct and accessible
- Ensure certificate is in PEM format
- Check certificate validity:
openssl x509 -in cert.crt -noout -dates - Verify certificate hostname matches LDAP server
Performance Considerations
- LDAP login path: LDAP mode performs authenticate, profile lookup, and group lookup per login.
- Retry impact: LDAP operations use retry logic (
retry), which improves resilience but can increase latency during outages. - Azure AD login path: Azure mode performs token exchange,
/meprofile lookup, and/me/memberOfgroup retrieval. - Large group memberships: Azure group retrieval is paged (
top(999)with skip token), so users in many groups may have slower login. - Default group fallback:
defaultGroupis prepended when configured, reducing role resolution failures for users with limited directory groups.
Security Considerations
Azure AD
- OAuth2 Protocol: Uses industry-standard OAuth2; credentials never transmitted to Countly
- Client Secret Protection: Store in secure configuration; rotate periodically
- Least Privilege: Limit Graph permissions to only what is needed for profile/group lookups
- Redirect URI Safety: Keep callback URI strict and exact in Azure app registration
LDAP
- TLS/SSL: Always use
ldaps://in production; never send credentials over unencrypted connection - Password Encryption: Use
countly encryptto encrypt bind password in config files - Service Account: Bind account should have minimal permissions (read-only on base DN)
- Network Isolation: LDAP traffic should remain on internal network only
- Certificate Validation: Ensure
tlsCertpoints to a valid readable certificate whentlsEnabled: true
Both Modes
- Separate Service Accounts: Never use personal AD accounts for LDAP bind or Azure AD service principal
- Audit Logging: Enable authentication logging to detect suspicious patterns
- Conditional Access: For Azure AD, consider using Conditional Access policies
- MFA Integration: Azure AD supports MFA; enable for additional security
- Regular Rotation: Rotate passwords and secrets periodically (every 90 days)
Integration with Other Features
The Active Directory feature integrates with Countly's core authentication and applies to:
- User Management: Authenticated users stored in
countly.members - Group Management: AD group mappings applied to Countly group permissions
- Admin Console: Admin users authenticated via AD have roles based on group mappings
- Permission System: User permissions determined by AD group mappings
- App Management: Per-app AD group settings stored in application configuration
Comparison: Azure AD vs LDAP
| Feature | Azure AD | LDAP |
|---|---|---|
| Deployment | Cloud (SaaS/Office 365) | On-premises (Active Directory) |
| Protocol | OAuth2 | LDAP/LDAPS |
| User Management | Azure AD Portal | Active Directory Users & Computers |
| MFA Support | Native/Conditional Access | Via LDAP server settings |
| Scalability | Multi-tenant cloud | Single organization/tenant |
| Setup Complexity | Low (OAuth2 registration) | Medium (LDAP configuration) |
| Security | Token-based, industry-standard | Direct authentication, TLS optional |
| Ideal For | SaaS deployments, multi-org | Enterprise, on-premises infrastructure |
Upgrading/Migrating Between Modes
To migrate from LDAP to Azure AD:
- Test Azure AD configuration on development/staging instance
- Verify group mappings work with Azure AD tenant
- Document current LDAP groups and Azure AD equivalents
- Plan switchover during maintenance window
- Notify users of authentication changes
- Keep LDAP as fallback during transition period
- Monitor authentication logs post-migration for issues
Related Documentation
Implementation details
Database Collections
The Active Directory feature stores group mappings in existing Countly collections:
| Collection | Purpose |
|---|---|
countly.members | User accounts created via AD authentication; includes mapped AD groups in user roles |
countly.apps | Application records; extended with ad_group_admin, ad_group_user, ad_group_marketing fields for per-app group settings |
countly.groups | Countly permission groups used during AD/Azure group-to-role mapping |
No separate collections are created; AD configuration integrates directly with core Countly collections.