caddy-security: authentication and authorization bolted onto Caddy
🔐 Authentication, Authorization, and Accounting (AAA) App and Plugin for Caddy v2. 💎 Implements Form-Based, Basic, Local, LDAP, OpenID Connect, OAuth 2.0 (Github, Google, Facebook, Okta, etc.), SAML Authentication. MFA/2FA with App Authenticators and Yubico. 💎 Authorization with JWT/PASETO tokens. 🔐
At a glance
- What is it?
- A Caddy v2 plugin set that implements form based, LDAP, OIDC, OAuth and SAML login, authorizes requests with JWT or PASETO tokens, and ships hundreds of end to end tests in the repository root.
- Who is it for?
- This plugin is a good fit when you run Caddy in front of services that have no authentication of their own and you want a single place to enforce login and per path access, especially if your identity provider is OIDC or SAML. It is a poor fit if you would rather keep authorisation inside your applications, because the whole design pushes access decisions into Caddyfile policy.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 9 days ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 28, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Three plugins, one security app
The README describes the project as a security app with authentication and authorization plugins for Caddy v2, and then names the three parts. The authentication plugin implements form based, basic, local, LDAP, OpenID Connect, OAuth 2.0 and SAML authentication. The authorization plugin handles HTTP request authorization based on JWT and PASETO tokens. The credentials plugin manages credentials for various integrations.
Two protocol choices in that list are worth pausing on. PASETO alongside JWT is not a casual addition; PASETO is designed to avoid the algorithm confusion and token parsing problems that have affected JSON web tokens, and supporting both means the plugin can issue a token type without the historical baggage. Supporting SAML alongside OIDC matters for enterprise identity providers, since SAML is still the common protocol in a lot of organisations that have not moved to OIDC.
The supported OAuth 2.0 providers are named in the repository description rather than the README, and include GitHub, Google, Facebook and Okta. Local authentication means credentials checked against something the plugin manages itself, which is the fallback for testing and for small internal deployments with no identity provider at all.
Documentation that moved into the repository as skills
The most unusual thing about this project is where its documentation now lives, and the README explains the move rather than hiding it. Documentation was previously hosted at docs.authcrunch.com, and the repository is now shifting to skill based documentation intended to help both humans and AI agents working with the codebase.
The consequence for a reader is concrete. Instead of a documentation site with a table of contents, you find `.codex/` directories holding markdown reference files, and the README links to them by path: one on runtime ownership and reload behaviour, one under a configuration state skill about persistent runtime state, one under coding directives about runtime lifecycle, one under scripts and automation about security dependency version, plus testing and CI and release and versioning references.
That is a genuine trade-off. The material is closer to the code and updated alongside it, which is good for accuracy and poor for browsing. There is no single page that tells you how to configure LDAP, and no getting started guide to follow top to bottom. If you are evaluating this plugin, plan to read a set of markdown files in the repository rather than a manual online, and expect the README's own configuration advice to consist of links.
Runtime ownership and why reload is not enough
One paragraph in the README carries more operational weight than the rest of the installation guidance combined. To retain sessions and generated signing keys across restarts, you need to enable persistent runtime state. The plugin supports portals and direct OAuth policies without a portal. And persistent deployments require a complete stop and start, because overlapping reload is rejected.
That last clause is the real constraint. In Caddy, reloading configuration without dropping the process is the normal way to apply changes, and most Caddy plugins assume that model. This one does not, at least when persistence is on, because sessions and signing keys have to survive. A configuration change that looks routine in a Caddyfile therefore becomes a restart window.
The linked reference explains the underlying behaviour in more detail: request draining, cleanup of failed replacements, and the restriction on overlapping runtimes that share a local identity file. Request draining matters for the same reason, since you do not want in flight requests dropped during a security change. If you are running this in production with automatic config reloads, this is the section to read before you wire up the pipeline that updates your Caddyfile.
How to get the binary and how to check what you got
Installation is not a package manager line in the README, it is a download link. The README points at Caddy's download API with the plugin enabled, offering Windows and Linux builds, and the URL encodes the plugin as a GitHub module reference at version v1.3.0 alongside caddy-trace at v1.1.13. In practice this means you request a Caddy build with the module compiled in rather than installing a plugin package at runtime.
For command line use there is a separate binary, `caddy-authenticator`, described as being for standalone command line portal login with named profiles, with release archives for Linux, macOS and Windows on both amd64 and arm64.
There is one diagnostic worth knowing. Running `bin/authcrunch security version` displays the linked go-authcrunch version, and the README points at a reference on security dependency version for the module replacement details behind it. That matters because the plugin delegates the heavy authentication lifting to a separate library, go-authcrunch, and the go.mod pins it at v1.3.8. Knowing which version of that library is linked into your binary is the difference between diagnosing a behaviour difference and guessing at it.
The build itself is pinned tightly: the go.mod requires Caddy v2.11.4, and the Makefile carries the same version string for its build target.
The test suite as a signal about how this is built
The root of the repository is unusual, and it is the clearest signal of the project's working style. Alongside `app.go`, `app_config.go` and `caddyfile.go` sit a long list of files whose names end in `_e2e_test.go` and `_test.go`: `admin_api_e2e_test.go`, `app_lifecycle_e2e_test.go`, `authentication_challenges_webauthn_e2e_test.go`, `authorization_oauth_e2e_test.go`, `caddyfile_authn_token_refresh_test.go`, and many more. There are Caddyfile adapter files too, including `caddyfile_adapt_test.go` and separate adapters for authentication, authorization and ACL shortcuts.
The build instructions match. Run `make dep` to download module dependencies and resolve the pinned tested tool, then `make test` for race enabled Go tests and coverage, and open `.coverage/index.html` for the report dashboard. There is `make run-reports` to rebuild reports from recorded evidence without rerunning the tests, and `make ci-check` which runs version checks, automation fixtures, the full Go suite and the Caddy binary build.
The CI description is specific in a way that suggests it is enforced. Release publication requires the same gate, GitHub Actions uploads the complete report bundle under a versioned name including failure evidence, and that bundle is retained for 14 days. The Makefile sets a test timeout of 45 minutes with a comment that the limit applies to the whole package including serial Caddy end to end journeys, which tells you these tests start real servers rather than mocking them.
Editorial conclusion
This plugin is a good fit when you run Caddy in front of services that have no authentication of their own and you want a single place to enforce login and per path access, especially if your identity provider is OIDC or SAML. It is a poor fit if you would rather keep authorisation inside your applications, because the whole design pushes access decisions into Caddyfile policy. Check two things before you commit: that the identity provider you need is among the listed protocols, and that you can accept the runtime ownership model, where a persistent deployment needs a complete stop and start rather than a reload. Version 1.3.0 shipped on 2026-09-28 and the linked go-authcrunch version is checkable from the binary itself.
Frequently asked questions
Which authentication protocols does caddy-security support?
The README lists form based, basic, local, LDAP, OpenID Connect, OAuth 2.0 and SAML authentication in the authentication plugin. Authorization of requests is handled separately using JWT or PASETO tokens, and a credentials plugin manages credentials for integrations.
Does caddy-security support SAML as well as OIDC?
Yes. SAML appears in the README's list of authentication methods alongside OpenID Connect and OAuth 2.0, alongside form based, basic, local and LDAP. The repository description also names GitHub, Google, Facebook and Okta as supported OAuth 2.0 providers.
Can I reload a caddy-security configuration without restarting Caddy?
Not when persistence is enabled. The README states that persistent deployments require a complete stop and start, because overlapping reload is rejected, and that persistent runtime state is needed to retain sessions and generated signing keys across restarts. A linked reference in the repository covers request draining and runtime ownership in more detail.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/greenpau-caddy-security)