Choosing Between LDAP and Local Authentication in Forgejo (and Configuring LDAP Safely)
Decide between Forgejo's local accounts and LDAP authentication with a compact comparison, then configure an LDAP source safely — including a fallback admin account and pre-flight ldapsearch validation.
25 May 2026, 19:31 UTC

The decision: where do Forgejo user identities live?
If you run Forgejo for a team, sooner or later you face a choice: keep accounts in Forgejo's built-in local database, or delegate authentication to an existing directory via LDAP (Lightweight Directory Access Protocol), such as Active Directory, OpenLDAP, or FreeIPA. The useful takeaway: LDAP is worth it when you already operate a directory and want one password and one offboarding process per person; local auth is the right call for small, standalone instances. The dangerous mistake is switching to LDAP without keeping a local admin account, because a bad bind configuration can lock everyone out.
Comparing the supported options
| Criteria | Local authentication | LDAP authentication |
|---|---|---|
| Setup effort | None; built in by default | Requires server address, bind DN, TLS settings, attribute mapping |
| Identity management | Accounts created and disabled inside Forgejo only | Centralised; one account works across many applications |
| Offboarding | Manual per instance | Disable the directory account once; access ends everywhere |
| Availability risk | Self-contained | Login fails or slows if the LDAP server is unreachable |
| Lockout risk | Low | A wrong bind DN or filter can reject every user |
| Fit | Personal instances, small teams, no existing directory | Organisations with AD/OpenLDAP/FreeIPA already in place |
The options are not mutually exclusive. Forgejo supports multiple authentication sources, and the recommended pattern is LDAP for regular users plus one local administrator account reserved for emergencies.
Trade-offs that matter in practice
Availability becomes a dependency. Every login now involves a network round trip to the directory. If the LDAP server is down or slow, Forgejo logins fail or stall. Plan for a reachable, redundant directory before migrating.
TLS is effectively mandatory. LDAP binds send credentials over the wire. Use LDAPS (port 636) or StartTLS with a certificate Forgejo can verify. Skipping verification (SkipTLSVerify) is acceptable only as a temporary diagnostic, never in production.
Group mapping is a second decision. Authenticating a user is only half the job. Decide whether Forgejo team membership stays managed inside Forgejo (simpler) or is synchronised from LDAP groups via the group team mapping feature (more central control, more configuration to get wrong).
Concrete implementation: adding an LDAP source
The safest path is the web UI, because Forgejo validates the form before saving. Log in as a local administrator, go to Site Administration → Authentication Sources → Add Authentication Source, and choose LDAP (via BindDN). A typical OpenLDAP configuration looks like this:
- Host:
ldap.example.com, Port:636, enable TLS - Bind DN:
cn=forgejo-bind,ou=service-accounts,dc=example,dc=com— a dedicated read-only service account, never a person's account - User Search Base:
ou=people,dc=example,dc=com - User Filter:
(&(objectClass=inetOrgPerson)(uid=%s))—%sis replaced with the login name the user types - Username attribute:
uid; Email attribute:mail
Forgejo stores the source in its database; the equivalent settings can also be reviewed in app.ini under [service] and the generated LDAP source entry. After saving, no restart is normally required for sources added through the UI, but if you edit app.ini directly you must restart the Forgejo service (for example, sudo systemctl restart forgejo on a systemd host, run with root or sudo privileges).
Before saving anything, test the bind and search from the Forgejo host itself with ldapsearch (part of the openldap-clients or ldap-utils package, run as any user with network access to the directory):
ldapsearch -x -H ldaps://ldap.example.com:636 \
-D "cn=forgejo-bind,ou=service-accounts,dc=example,dc=com" \
-W -b "ou=people,dc=example,dc=com" \
"(uid=testuser)" uid mailThis prompts for the bind password and should return the test user's entry with uid and mail attributes. If this command fails, Forgejo will fail too — fix DNS, firewall, TLS trust, or the bind credentials here first. Risk note: -x -W sends the password over the TLS session; run this only over LDAPS or StartTLS.
Validating the result and protecting yourself
- Confirm a local admin account exists and its password works before any LDAP user logs in. Test it in a private browser window.
- Log in with a test LDAP user. On first successful bind, Forgejo creates a local user record linked to the LDAP source.
- Check the Forgejo log (journald with
journalctl -u forgejo, or the log file configured inapp.ini) for LDAP bind success or failure messages if login fails — an "invalid credentials" error usually means the bind DN or user filter is wrong, not the user's password. - If you enabled group team mapping, verify the test user lands in the expected Forgejo team; a wrong group filter silently grants no teams rather than producing an error.
Limitations
LDAP gives you authentication, not full account lifecycle sync: deleting a directory user does not delete their Forgejo account or repositories, it only blocks login. Password changes happen in the directory, not in Forgejo. And because behaviour details vary across Forgejo versions, confirm the exact field names in your version's admin UI and documentation before rolling out to all users.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.