Enterprise authentication that fits in a single 10Β MB binary.
Active Directory Β· Kerberos SSO Β· a standard OIDC provider Β· signed JWTs β running in 3 commands.
Quick Start Β· API Reference Β· ADΒ +Β Kerberos Β· SDKs Β· Security Audit Log Β· Contributing
Setting up authentication shouldn't mean standing up a Java cluster, a database, a cache, and a weekend. SimpleAuth is the whole identity layer β Active Directory login, transparent Windows SSO, a standards-compliant OIDC provider, and RS256 JWTs β in one Go binary you can scp to a box and run.
No Java. No mandatory database. No config files after first run. Everything is managed from a built-in admin UI, and a domain-joined machine gets you to two-click Kerberos SSO. Drop it in, point your app at it, ship.
docker run -d -p 8080:8080 \
-e AUTH_HOSTNAME=auth.example.com \
-e AUTH_ADMIN_KEY=change-me \
-e AUTH_REDIRECT_URIS="https://myapp.example.com/*" \
-v simpleauth-data:/data \
simpleauth
# β admin UI at https://auth.example.com/sauth/admin. That's it.It's powerful. Everything a real identity provider needs, nothing watered down:
- πͺͺ Active Directory & LDAP β bind login, attribute sync, group membership, auto-discovery.
- π« Transparent Kerberos / SPNEGO SSO β users on the domain are logged in without typing anything. SSO setup is a downloadable PowerShell script and one paste-back β no
ktpass, no keytab files, no hand-edited LDAP. - π A standard OIDC provider β discovery, authorization-code flow with PKCE, token, userinfo, JWKS, introspection, end-session. Works with any OIDC client library, in any language.
- π RS256 JWTs β auto-generated RSA-2048 keys, a JWKS endpoint for offline verification, single-use refresh-token rotation with family replay detection.
- π₯ Roles, permissions & groups β resolved into the token your app already trusts.
- π’ One directory, many apps β register multiple apps that each own their own roles, permissions, and allowed users. Users sign in once; tokens are audience-scoped, so a token minted for app A is rejected by app B. (details below)
It's simple. The kind of simple you feel in the first five minutes:
- π¦ One ~10 MB binary. No runtime, no JVM, no sidecars. BoltDB is embedded β zero external dependencies to start.
- π₯οΈ A real admin UI (dark mode included) β users, roles, LDAP, audit log, settings, database, all on a page. No XML, no
kcadm.sh. - β‘ 3 commands to running, and users are auto-created on first login from any provider β no import, no sync, no migration job.
- π§© Embeddable β
import "simpleauth/pkg/server"and your Go app is the auth server. - π Official SDKs for JavaScript/TypeScript, Go, Python, and .NET, each with framework middleware.
| Keycloak | ADFS | SimpleAuth | |
|---|---|---|---|
| Setup | Hours (Java + Postgres + cache) | Hours + Windows Server | 3 commands |
| Footprint | ~500 MB+ | A domain controller | ~10 MB binary |
| External deps | Database + cache required | Windows infra | None (optional Postgres) |
| Kerberos SSO | Manual, fiddly | Built-in but rigid | Two-click auto-config |
| OIDC provider | Full | Claims-based | Full |
| Per-app authorization | Realms + clients (heavy) | Relying-party trusts | Built-in, audience-scoped |
| Admin experience | Steep | Windows-only MMC | One web page |
| REST API | Sprawling | None | Clean JSON + JWTs |
Docker:
docker run -d -p 8080:8080 \
-e AUTH_HOSTNAME=auth.example.com \
-e AUTH_ADMIN_KEY=my-secret-admin-key \
-e AUTH_REDIRECT_URIS="https://myapp.example.com/callback,https://myapp.example.com/*" \
-e AUTH_CORS_ORIGINS="https://myapp.example.com" \
-v simpleauth-data:/data \
simpleauthBinary:
./simpleauth init-config # generates simpleauth.yaml
vim simpleauth.yaml # set hostname, redirect URIs, admin key
./simpleauth # runningOpen the admin UI at https://<hostname>/sauth/admin and sign in with your admin key. (Omit AUTH_ADMIN_KEY and one is generated on first run and printed to the logs.)
For any real deployment, set three things:
AUTH_HOSTNAME,AUTH_ADMIN_KEY, andAUTH_REDIRECT_URIS. Without an allowlist, every login redirect is rejected β by design.
New to OAuth/OIDC? The Quick Start walks you from zero to a logged-in user, and the Integration Guide explains every term (JWT, redirect URI, CORS, the /sauth base path) in plain language.
Pick whichever fits β you can mix them:
1. Direct REST β best for mobile, SPAs with a backend, and server-to-server.
curl -X POST https://auth.example.com/sauth/api/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"alice","password":"secret123"}'
# β { "access_token": "eyJβ¦", "refresh_token": "eyJβ¦", "expires_in": 900 }2. Hosted login page β best for web apps that don't want to build a login form. Redirect to β¦/sauth/login?redirect_uri=https://myapp/callback; SimpleAuth (or Kerberos SSO) authenticates the user and hands the tokens back on the callback.
3. Standard OIDC β best when you already use an OIDC client library or need an id_token. Point your library at the discovery URL and you're done:
https://auth.example.com/sauth/.well-known/openid-configuration
Then verify tokens offline against the JWKS endpoint (no network call per request), or call /sauth/api/auth/userinfo to introspect. Full walkthrough with every flow: docs/API.md.
| Language | Package | Install |
|---|---|---|
| JavaScript / TypeScript | @simpleauth/js |
npm install @simpleauth/js |
| Go | github.com/bodaay/simpleauth-go |
go get github.com/bodaay/simpleauth-go |
| Python | simpleauth |
pip install simpleauth |
| .NET | SimpleAuth |
reference the project |
Every SDK does login/refresh/userinfo, offline JWT verification with cached JWKS, role/permission helpers (HasRole, HasPermission, HasAnyRole), and ships middleware for Express, net/http, FastAPI/Flask/Django, and ASP.NET Core. See examples/.
Most auth servers make you choose: one shared login or per-app control. SimpleAuth gives you both β one directory, one sign-in, but every app owns its own authorization.
- Register an app β it gets an
app_id+app_secret. The root admin adds apps; existing single-app deployments auto-migrate to a default app, unchanged. - Tokens are audience-scoped. Every token carries
aud= the app it was minted for, so a token forbillingis rejected byanalyticsβ the SDK'saudienceoption enforces it. No more one-token-rules-them-all. - Each app owns its roles, permissions, and assignments.
viewerin one app is unrelated toviewerin another. Flip onrequire_assignmentand an app admits only the users it has explicitly assigned. - Apps manage themselves. An app configures its own roles and assignments using its
app_id/app_secret(HTTP Basic or a short-lived management token) and an idempotentPOST /api/app/bootstrapyou can run on every deploy β no master admin key in your pipeline. - App-local users. An app can own users who aren't in your directory at all β perfect for a customer portal β scoped to that app and never shared across apps.
A developer's whole integration becomes: get an app_id/app_secret β bootstrap your roles on deploy β point the SDK at SimpleAuth with audience set β verify(). All four SDKs ship the app-management helpers (appBootstrap, getAppAuthz/setAppAuthz, app-local user CRUD) β see the app-integration examples in examples/ and the Apps reference in docs/API.md.
Think Azure AD / Entra app registrations β one directory, many apps, per-app roles, audience-scoped tokens β without the cluster.
|
Authentication
|
Tokens & authorization
|
|
Admin UI (dark mode, one page)
|
Ops & storage
|
SimpleAuth guards the front door, so security isn't a feature β it's the product. A few things we do differently:
- A public, living audit trail.
SECURITY-AUDIT.mdlogs every security review, finding, and fix β dated, with stable IDs, by different AI models and humans over time. Nothing is swept under the rug; evenWONTFIXdecisions are written down with rationale. It's unusual to publish your own audit log. We think a project that protects logins should. - Sane defaults that fail closed. Redirect URIs are a strict allowlist (empty = reject all). The confidential OIDC grants (
password,client_credentials) and token introspection are disabled unless you setAUTH_CLIENT_SECRET. Trusted proxies default to trust none. - Modern token hygiene. RS256 only (no alg-confusion), JWKS with a stable key id, single-use refresh tokens with replay detection, an access-revocation kill switch, and authenticator-verified Kerberos with a replay cache and clock-skew enforcement.
- Defense in depth. bcrypt password hashing with a configurable policy and history, account lockout, per-IP rate limiting, CSRF tokens, and security headers across responses.
Found something? Please open a security advisory (or a private report) rather than a public issue β see Contributing. Then add it to the audit log; that's exactly what it's for.
This project is public on purpose. SimpleAuth protects authentication, and security software gets better with more eyes on it. If you've ever wanted to work on an auth server that's small enough to actually read end-to-end in an afternoon β this is that codebase.
Especially valuable:
- π Security review. Read
SECURITY-AUDIT.md, then audit a flow (login, refresh rotation, Kerberos, OIDC grants, the store layer) and send what you find β a PR, an issue, or a new audit pass appended to the log. The file even contains the prompt we hand to each reviewer. - π§© More SDKs & framework middleware. Rust, Java, PHP, Ruby β or deeper middleware for the four we already ship.
- π Docs & examples. A clearer explanation, a new framework example in examples/, a fixed typo β all welcome.
- π Bugs & papercuts. Edge cases in LDAP/Kerberos against real directories are gold.
Get going in a minute:
git clone <your-fork>
cd SimpleAuth
go build ./... # builds the single binary
go test ./... # full suite (no external services needed)
go vet ./...Open a PR with a focused change and a test, and keep the trio in sync β code, docs, and the SDKs/examples for any surface you touch. New features ship with all of it. First time here? Open an issue describing what you'd like to do and we'll point you at the right file.
OIDC endpoints
Discovery: GET /.well-known/openid-configuration
| Endpoint | Method | Path |
|---|---|---|
| Authorization | GET |
/realms/{issuer}/protocol/openid-connect/auth |
| Token | POST |
/realms/{issuer}/protocol/openid-connect/token |
| UserInfo | GET/POST |
/realms/{issuer}/protocol/openid-connect/userinfo |
| JWKS | GET |
/realms/{issuer}/protocol/openid-connect/certs |
| Introspection | POST |
/realms/{issuer}/protocol/openid-connect/token/introspect |
| End Session | GET/POST |
/realms/{issuer}/protocol/openid-connect/logout |
authorization_code and refresh_token are public flows (auth-code supports PKCE/S256). password, client_credentials, and introspection are confidential β disabled unless AUTH_CLIENT_SECRET is set, then require that secret.
Direct API
| Method | Path | Description |
|---|---|---|
POST |
/api/auth/login |
Login, get JWT tokens |
POST |
/api/auth/refresh |
Rotate refresh token |
GET |
/api/auth/userinfo |
Current user from the JWT |
GET |
/api/auth/negotiate |
Kerberos/SPNEGO SSO |
POST |
/api/auth/impersonate |
Token as another user (admin) |
POST |
/api/auth/reset-password |
Change password (authenticated) |
GET |
/login Β· /logout Β· /account |
Hosted pages |
GET |
/.well-known/jwks.json |
JWKS public keys |
GET |
/health |
Health check |
Admin API (all require Authorization: Bearer <admin-key>)
| Category | Endpoints |
|---|---|
| Bootstrap | POST /api/admin/bootstrap β idempotent: define roles, permissions, ensure users |
| Users | CRUD /api/admin/users, merge/unmerge, disable, unlock, sessions |
| Roles & Permissions | /api/admin/roles, /api/admin/permissions, /api/admin/role-permissions |
| LDAP | CRUD /api/admin/ldap, auto-discover, import/export, test |
| AD / Kerberos | GET /api/admin/setup-script, /api/admin/ldap/:id/setup-kerberos |
| Linux SSO | GET /api/admin/linux-setup-script |
| Settings / DB / Ops | runtime settings, migrate/switch backends, backup, restore, audit, restart |
Full reference with request/response examples: docs/API.md.
Essential configuration
| Variable | Default | Description |
|---|---|---|
AUTH_HOSTNAME |
OS hostname | FQDN for TLS cert and Kerberos SPN |
AUTH_ADMIN_KEY |
auto-generated | Admin API key |
AUTH_BASE_PATH |
/sauth |
URL path prefix (every URL starts here) |
AUTH_REDIRECT_URIS |
Allowed redirect URIs, comma-separated (* wildcards) |
|
AUTH_CORS_ORIGINS |
Browser origins allowed to call SimpleAuth | |
AUTH_POSTGRES_URL |
Enables the Postgres backend | |
AUTH_TLS_DISABLED |
false |
Disable TLS (reverse-proxy mode) |
AUTH_TRUSTED_PROXIES |
Trusted proxy CIDRs (default: trust none) | |
AUTH_CLIENT_SECRET |
Enables confidential OIDC grants + introspection | |
AUTH_JWT_ACCESS_TTL |
15m |
Access token lifetime |
AUTH_JWT_REFRESH_TTL |
720h |
Refresh token lifetime |
AUTH_ENABLE_SESSION_SSO |
false |
Shared SSO session cookie across apps |
AUTH_AUTO_SSO |
false |
Auto-attempt Kerberos SSO on the login page |
Everything else β password policy, lockout, rate limiting, audit retention β is in docs/CONFIGURATION.md. Behind nginx/Traefik/Caddy/HAProxy? See docs/REVERSE-PROXY.md (and mind the Kerberos header buffers).
- Admin UI β LDAP Providers β AD Setup Script. Enter a service-account name, download the PowerShell script.
- Run it on any domain-joined machine β it creates the account, registers SPNs, and exports a config file. No
ktpass. - Paste the config back in the UI. SimpleAuth builds the keytab in memory and enables SSO immediately.
Full guide + troubleshooting: docs/ACTIVE-DIRECTORY.md.
cfg := server.Defaults()
cfg.Hostname = "myapp.example.com"
cfg.AdminKey = "my-secret-key"
cfg.DataDir = "./auth-data"
cfg.BasePath = "/auth"
sa, err := server.New(cfg, ui.FS()) // pass nil UI for API-only
if err != nil { log.Fatal(err) }
defer sa.Close()
mux := http.NewServeMux()
mux.Handle("/auth/", http.StripPrefix("/auth", sa.Handler()))
// your app handles everything else
http.ListenAndServe(":8080", mux)Your app and its auth server, one process, one deploy. See docs/ARCHITECTURE.md.
| Document | What's inside |
|---|---|
| Quick Start | Zero to a logged-in user in 5 minutes |
| API Reference | Every endpoint, every term, with examples |
| Configuration | All config options |
| Architecture | How it works under the hood |
| Active Directory | AD, Kerberos, troubleshooting |
| Reverse Proxy | nginx, Traefik, Caddy, HAProxy |
| SDK Guide | Client SDK usage |
| Security Audit Log | Every review, finding, and fix |
MIT β see LICENSE. Build something with it, and if it makes your auth simpler, β the repo so the next person finds it.