Skip to main content

LDAPGate

LDAPGate

Lightweight LDAP/AD authentication gateway for Python web apps. Install it, configure it, done.

Features

  • Two deployment modes — standalone reverse proxy or drop-in FastAPI middleware
  • WebDAV + browser in one — browsers get a login form; WebDAV clients (Windows, macOS Finder, curl) get a Basic auth challenge — same endpoint, no extra config
  • Pure Python LDAP — no OS-level libs required, uses ldap3
  • Signed cookie sessions — stateless, no server-side session storage
  • OpenLDAP and Active Directory — uid= and sAMAccountName= out of the box
  • Optional group gating — restrict access to members of a specific LDAP group
  • Header injection — injects X-Forwarded-User for downstream apps
  • Bundled login form — responsive, dark/light mode, customisable, works air-gapped

Install

pip install ldapgate

Config file

Both modes share the same ldapgate.yaml:

ldap:
  url: ldaps://dc.example.com:636
  bind_dn: CN=svc,CN=Users,DC=example,DC=com
  bind_password: secret
  base_dn: DC=example,DC=com
  user_filter: "(sAMAccountName={username})"         # AD; OpenLDAP: (uid={username})
  # LDAPGate requires at least one authorization rule by default:
  group_dn: CN=app-users,CN=Users,DC=example,DC=com  # restrict by group
  allowed_users:                                      # or restrict by local allowlist
    - alice
    - bob
  timeout: 10                                      # LDAP operation and total login deadline
  tls_validate: REQUIRED                             # NONE | OPTIONAL | REQUIRED
  tls_ca_cert_file: /etc/ssl/certs/internal-ca.pem  # optional — custom CA bundle
  tls_client_cert_file: /etc/ssl/certs/client.pem   # optional — mutual TLS client cert
  tls_client_key_file: /etc/ssl/private/client.key  # optional — mutual TLS client key

proxy:
  listen_host: 0.0.0.0
  listen_port: 9000
  backend_url: http://localhost:8080
  secret_key: change-me-to-something-random
  session_ttl: 3600
  idle_timeout: 0                                  # set >0 to expire inactive browser sessions
  user_header: X-Forwarded-User
  login_path: /_auth/login
  logout_path: /_auth/logout
  app_name: MyApp
  mask_usernames_in_logs: true                    # set false to log full usernames
  secure_cookies: false                              # set true when behind HTTPS

All settings can also be provided via environment variables using __ as a separator — e.g. LDAP__URL, PROXY__SECRET_KEY.

Corporate / Active Directory setup

For corp environments with internal CAs where cert validation isn't feasible:

ldap:
  url: ldaps://dc.example.com:636
  tls_validate: NONE
  # ... other settings ...

⚠️ Warning: tls_validate: NONE disables all TLS certificate validation and makes you vulnerable to man-in-the-middle attacks. Whenever possible, use tls_ca_cert_file to trust your internal CA instead.

For plain LDAP with STARTTLS:

ldap:
  url: ldap://dc.example.com:389
  use_starttls: true

Mode 1 — Standalone Reverse Proxy

Run ldapgate as a standalone process in front of any app.

Browser / WebDAV client → ldapgate :9000 → backend app :8080
ldapgate serve --config ldapgate.yaml

All traffic is intercepted by ldapgate before reaching the backend. Authenticated requests are forwarded with the X-Forwarded-User header set to the verified username. Apps can point their logout link at the configured logout_path (default /_auth/logout) to clear the session.

WebDAV clients receive a 401 WWW-Authenticate: Basic challenge automatically and authenticate per-request via HTTP Basic auth — no session cookie needed.


Mode 2 — FastAPI Middleware

Drop ldapgate auth directly into an existing FastAPI app — no separate process.

from fastapi import FastAPI
from ldapgate.config import load_config
from ldapgate.middleware import add_ldap_auth

app = FastAPI()
config = load_config("ldapgate.yaml")
add_ldap_auth(app, config)

@app.get("/api/data")
async def data(request):
    return {"user": request.state.user}  # authenticated username

add_ldap_auth registers the login/logout routes and attaches the middleware in one call. The authenticated username is available as request.state.user and is also injected as the configured user_header into the request headers.

WebDAV with middleware

The middleware handles both browser and WebDAV clients on the same app instance:

Client Auth flow
Browser Redirected to login form → session cookie
WebDAV (Windows, macOS Finder, curl) 401 WWW-Authenticate: Basic challenge → Basic auth per-request

No extra routes or config needed — if a request arrives without a session cookie and without Accept: text/html, the middleware issues a 401 with a WWW-Authenticate: Basic header. The client sends credentials, the middleware validates against LDAP, and the request proceeds.

Successful Basic auth checks are cached briefly in memory by default (proxy.basic_auth_cache_ttl: 60) so chatty WebDAV clients like macOS Finder do not force a fresh LDAP bind for every metadata request. Set it to 0 to disable the cache.

allowed_users and group_dn apply to both flows — a user blocked by those settings is rejected regardless of whether they authenticated via cookie or Basic auth.

Example — xwing file server with WebDAV:

from fastapi import FastAPI
from ldapgate.config import load_config
from ldapgate.middleware import add_ldap_auth
from xwing.app import create_app
from xwing.config import Settings

xwing_settings = Settings(root_dir="/srv/files", users_config="users.yaml")
app = create_app(xwing_settings)

ldap_config = load_config("ldapgate.yaml")
add_ldap_auth(app, ldap_config)

Windows users can now map http://your-server:8989/ as a network drive:

net use Z: http://your-server:8989/ /user:alice /persistent:yes

macOS Finder: Go → Connect to Server (⌘K) → http://your-server:8989/


CLI reference

ldapgate serve [OPTIONS]

  --config PATH     Path to ldapgate.yaml (reads env vars if omitted)
  --host TEXT       Override listen host
  --port INTEGER    Override listen port
  --backend TEXT    Override backend URL
  --reload          Enable auto-reload (dev only)

Development

Requires uv.

git clone https://github.com/anudeepd/ldapgate
cd ldapgate
uv sync
uv run pytest

License

MIT

Metadata

Release files for ldapgate 0.1.27

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ldapgate 0.1.27
File Size Uploaded
ldapgate-0.1.27.tar.gz 156.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for ldapgate 0.1.27
File Interpreter ABI Platform
ldapgate-0.1.27-py3-none-any.whl Python 3 none any Details

Total release size: 299.6 kB

Release files / ldapgate-0.1.27.tar.gz

Download URL ldapgate-0.1.27.tar.gz
Size 156.4 kB
Tags Source
SHA-256 checksum
How to use checksums
489ab6e0fddab1b7cb87566dee50ed70130d0bde7a0ffc6f6977aa7ed2c8dc4f
BLAKE2b-256 checksum
How to use checksums
d9104c005f7ca934c8faa90075f61d90ed9f693ea6face6e530abffb7361fe99
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.23 {"installer":{"name":"uv","version":"0.11.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Fedora Linux","version":"44","id":"","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / ldapgate-0.1.27-py3-none-any.whl

Download URL ldapgate-0.1.27-py3-none-any.whl
Size 143.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
1f50e45b43f21bddc6777ca28f88ee9d4080cb2165a945b23778b72b8d276bfb
BLAKE2b-256 checksum
How to use checksums
5ab294e06f4b9e79e51b192a5a391e6863c9d85b1e4027e3168009e10f1853de
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.23 {"installer":{"name":"uv","version":"0.11.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Fedora Linux","version":"44","id":"","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

0.1.29

2 release files

0.1.28

2 release files

This release

0.1.27 This release

2 release files

0.1.26

2 release files

0.1.19

2 release files

0.1.18

2 release files

0.1.17

2 release files

0.1.16

2 release files

0.1.15

2 release files

0.1.13

2 release files

0.1.12

2 release files

0.1.11

2 release files

0.1.10

2 release files

0.1.9

2 release files

0.1.8

2 release files

0.1.7

2 release files

0.1.6

2 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page