SimpleAuth was built for Active Directory. This guide covers everything from creating a service account to setting up transparent Kerberos login.
Before you start, you need:
- An Active Directory domain (Windows Server 2012+ or later)
- A service account in AD for SimpleAuth (or admin rights to create one)
- Network access from the SimpleAuth server to your domain controller(s) on:
- LDAP: port 389 (or LDAPS: port 636)
- Kerberos: port 88 (only if using SPNEGO)
- DNS resolution of your domain controller hostnames
Create a dedicated service account in AD for SimpleAuth. This account is used to search for users and read their attributes. It does NOT need admin privileges.
- Open Active Directory Users and Computers
- Create a new user in an OU for service accounts (e.g.,
OU=Service Accounts) - Name:
svc-sauth-{deployment_name}(e.g.,svc-sauth-sauth; max 6 chars, letters only) - Set a strong password
- Check "Password never expires"
- Uncheck "User must change password at next logon"
New-ADUser -Name "svc-sauth-prod" `
-SamAccountName "svc-sauth-prod" `
-UserPrincipalName "svc-sauth-prod@corp.local" `
-Path "OU=Service Accounts,DC=corp,DC=local" `
-AccountPassword (ConvertTo-SecureString "YourStrongPassword" -AsPlainText -Force) `
-PasswordNeverExpires $true `
-CannotChangePassword $true `
-Enabled $trueTip: Use the server-side setup script instead — it handles all of this automatically including SPN registration and config export. Download it from the admin UI ("AD Script" button) or
GET /api/admin/setup-script.
The service account needs read access to user objects. By default, all authenticated users in AD can read the attributes SimpleAuth needs. No special delegation is required.
If your AD has restricted read permissions, the service account needs:
- Read access to
sAMAccountName,displayName,mail,department,company,title,memberOf,objectGUID
curl -k -X POST https://auth.corp.local:8080/api/admin/ldap \
-H "Authorization: Bearer YOUR_ADMIN_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Corporate Active Directory",
"url": "ldaps://dc01.corp.local:636",
"base_dn": "DC=corp,DC=local",
"bind_dn": "CN=svc-sauth-prod,OU=Service Accounts,DC=corp,DC=local",
"bind_password": "YourStrongPassword",
"username_attr": "sAMAccountName",
"use_tls": true,
"skip_tls_verify": false,
"display_name_attr": "displayName",
"email_attr": "mail",
"department_attr": "department",
"company_attr": "company",
"job_title_attr": "title",
"groups_attr": "memberOf",
"priority": 10
}'Navigate to /admin on your SimpleAuth instance in a browser and use the built-in admin UI to configure LDAP visually.
If your DNS is properly configured with SRV records, SimpleAuth can auto-discover your domain controllers:
curl -k -X POST https://auth.corp.local:8080/api/admin/ldap/auto-discover \
-H "Authorization: Bearer YOUR_ADMIN_KEY"curl -k -X POST https://auth.corp.local:8080/api/admin/ldap/test \
-H "Authorization: Bearer YOUR_ADMIN_KEY"If successful, try logging in:
curl -k -X POST https://auth.corp.local:8080/api/auth/login \
-H "Content-Type: application/json" \
-d '{
"username": "jsmith",
"password": "UserPassword123"
}'| Field | Example | Description |
|---|---|---|
url |
ldaps://dc01.corp.local:636 |
LDAP server URL. Use ldaps:// for LDAPS (port 636) or ldap:// for StartTLS (port 389). |
base_dn |
DC=corp,DC=local |
Base DN for user searches. Use your domain's DN. |
bind_dn |
CN=svc-sauth-prod,OU=Service Accounts,DC=corp,DC=local |
Full DN of the service account. |
bind_password |
(string) | Service account password. |
use_tls |
true |
Enable TLS. Should always be true in production. |
skip_tls_verify |
false |
Skip TLS certificate verification. Only for testing. |
| Field | Example | Description |
|---|---|---|
username_attr |
sAMAccountName |
The LDAP attribute used to match the login username. |
Common values:
sAMAccountName-- most common for AD (matches login name)mail-- useful for email-based loginuserPrincipalName-- foruser@domainformat
These map AD attributes to SimpleAuth user fields:
| Field | Default AD Attribute | Description |
|---|---|---|
display_name_attr |
displayName |
User's full display name |
email_attr |
mail |
User's email address |
department_attr |
department |
Department name |
company_attr |
company |
Company name |
job_title_attr |
title |
Job title |
groups_attr |
memberOf |
Group membership (multi-valued DN list) |
| Field | Default | Description |
|---|---|---|
priority |
0 |
Provider priority (reserved for future use). |
Kerberos enables transparent single sign-on for domain-joined machines. Users access your app in their browser and are authenticated automatically -- no password prompt.
- Browser requests a protected resource
- Your app redirects to SimpleAuth's negotiate endpoint
- SimpleAuth responds with
401 + WWW-Authenticate: Negotiate - Browser obtains a Kerberos ticket from the KDC for SimpleAuth's SPN
- Browser resends the request with the ticket
- SimpleAuth validates the ticket using its keytab
- SimpleAuth issues JWTs and redirects back to your app
SimpleAuth can set up Kerberos automatically using your AD admin credentials:
curl -k -X POST \
https://auth.corp.local:8080/api/admin/kerberos/setup \
-H "Authorization: Bearer YOUR_ADMIN_KEY" \
-H "Content-Type: application/json" \
-d '{
"admin_username": "admin@CORP.LOCAL",
"admin_password": "AdminPassword"
}'This command:
- Creates a Service Principal Name (SPN)
HTTP/auth.corp.local@CORP.LOCALin AD - Generates a keytab file in the data directory
- Configures SimpleAuth to accept SPNEGO tokens
Important: The hostname in your SimpleAuth config must match the hostname users use in their browser. The SPN is HTTP/{hostname}@{REALM}.
If you prefer to set things up manually:
1. Create the SPN in AD:
# On a domain controller or machine with RSAT tools
setspn -S HTTP/auth.corp.local svc-sauth-prod2. Generate a keytab:
# On Linux
ktutil
addent -password -p HTTP/auth.corp.local@CORP.LOCAL -k 0 -e aes256-cts-hmac-sha1-96
# (enter service account password)
wkt /etc/simpleauth/krb5.keytab
quit3. Configure SimpleAuth:
# In simpleauth.yaml
krb5_keytab: "/etc/simpleauth/krb5.keytab"
krb5_realm: "CORP.LOCAL"Or via environment variables:
AUTH_KRB5_KEYTAB=/etc/simpleauth/krb5.keytab
AUTH_KRB5_REALM=CORP.LOCALcurl -k -H "Authorization: Bearer ADMIN_KEY" \
https://auth.corp.local:8080/api/admin/kerberos/statusOpen https://auth.corp.local:8080/test-negotiate in a browser on a domain-joined machine. If Kerberos is working, you'll see your identity without entering a password.
Most browsers support SPNEGO out of the box for intranet sites. Some may need configuration:
Chrome/Edge: Add the SimpleAuth hostname to the AuthServerAllowlist policy or navigate to chrome://settings/ and ensure the host is in the Intranet zone.
Firefox: Navigate to about:config and add your SimpleAuth hostname to network.negotiate-auth.trusted-uris:
network.negotiate-auth.trusted-uris = auth.corp.local
To remove Kerberos configuration:
curl -k -X POST \
https://auth.corp.local:8080/api/admin/kerberos/cleanup \
-H "Authorization: Bearer YOUR_ADMIN_KEY"When a user authenticates via LDAP, SimpleAuth reads these attributes and stores them in the user record:
| SimpleAuth Field | Default AD Attribute | Example Value |
|---|---|---|
display_name |
displayName |
John Smith |
email |
mail |
jsmith@corp.local |
department |
department |
Engineering |
company |
company |
Acme Corporation |
job_title |
title |
Senior Software Engineer |
groups |
memberOf |
["CN=Engineering,OU=Groups,DC=corp,DC=local"] |
Attributes are refreshed on every login, so changes in AD are reflected automatically.
SimpleAuth identifies AD users by their objectGUID (a unique, immutable identifier). This means:
- Renaming a user in AD doesn't break their SimpleAuth identity
- Moving a user to a different OU doesn't break anything
- The identity mapping is
ldap:{objectGUID}
The memberOf attribute returns full DNs like:
CN=Engineering,OU=Groups,DC=corp,DC=local
These are included in JWT tokens as-is. Your app can parse the CN to get the group name, or compare full DNs for precision.
- Check that the domain controller is reachable:
telnet dc01.corp.local 636 - Check firewall rules between SimpleAuth and the DC
- If using LDAPS (port 636), ensure the DC has a valid TLS certificate
- Verify the Bind DN is the full distinguished name, not just the username
- Try the DN in
ldapsearch:ldapsearch -H ldaps://dc01.corp.local -D "CN=svc-sauth-prod,OU=Service Accounts,DC=corp,DC=local" -w password -b "DC=corp,DC=local" "(sAMAccountName=testuser)" - Check if the service account is locked out or disabled
- Check the
username_attr-- it must match the attribute users log in with (e.g.,sAMAccountName) - Verify the
base_dncontains the user's OU
- Your DC's certificate might be signed by an internal CA
- Add the CA certificate to the system trust store on the SimpleAuth server
- Or set
"skip_tls_verify": true(not recommended for production)
- Verify the
groups_attris set tomemberOf - Check that the user actually has group memberships in AD
- Some groups (like "Domain Users") don't appear in
memberOfbecause they're the primary group
- Verify the SPN exists:
setspn -L svc-sauth-prod - Check that the hostname in the URL matches the SPN:
HTTP/auth.corp.local - Verify DNS resolves the hostname from the client machine
- Check
kliston a client machine to see if a ticket was obtained - Try the test page:
https://auth.corp.local:8080/test-negotiate - Check SimpleAuth logs for "negotiate_failed" audit entries