ol.clave
Automatic HTTPS certificate management and renewal via ACME, implemented in pure Clojure with minimal dependencies
ol.clave is an ACME client for Clojure.
It gives you a lower-level API for implementing the ACME protocol itself when you need that much control. If you want to work directly with accounts, orders, authorizations, challenges, and certificate issuance, you can do that.
And if you do not want to live at RFC altitude all day, it also gives you a higher-level API for provisioning certificates from application code, managing them over time, and keeping them up to date. That is the part most people actually want. Ask for a cert. Renew the cert. Repeat.
ol.clave also includes adapters for wiring ACME into Jetty-based applications, plus helpers for HTTP-01 and TLS-ALPN-01 validation. For DNS validation, it gives you the hooks you need, but it does not ship DNS provider integrations by default. DNS provider integrations are future work. (If you are interested in that, get in touch.)
One of the design goals for ol.clave was as few dependencies as possible and avoid dragging in a bunch of Java ecosystem baggage.
At runtime there are exactly two hard dependencies. The first is babashka/json, which is a BYO JSON-library-library. On the JVM it will use a JSON provider from your classpath. In many applications that will just work because you already have one. If you care which provider gets picked, or want to force one, go read that project’s docs.
The second runtime dep is Peter Taoussanis’s Trove, which gives ol.clave a very lightweight way to emit signals and logging without forcing a backend on you. Same story there: wire it into whatever telemetry or logging stack you already use after reading Peter’s docs.
The no-dependencies choice has consequences. I did not want to pull in Bouncy Castle as a runtime dependency. It is large, it is heavy, and it is the kind of library that likes to start version fights when two things on your classpath want different releases. But ACME certificate provisioning still needs some plumbing that the JDK does not hand you directly (despite being distributed as part of the keytool util in every JDK package), especially around DER de/encoding, CSR generation, and a few X.509-adjacent details.
To be clear, ol.clave is not implementing any cryptography itself. The actual crypto primitives (RSA, ECC, etc) still come from the JVM. What ol.clave implements in pure Clojure is the narrow slice of encoding, decoding, and certificate-request machinery needed to make ACME work without the heavyweight runtime dependencies. That problem space is small enough to specify, small enough to test thoroughly and it isn’t a general-purpose PKI toolkit.
Project status: Experimental.
Installation
;; deps.edn
{:deps {com.outskirtslabs/clave {:mvn/version "0.0.0" }}}
;; Leiningen
[com.outskirtslabs/clave "0.0.0" ]
Quick Start
Start with one of the runnable examples in this repository:
-
examples/certificate.cljfor the higher-level certificate acquisition flow. -
examples/acme.cljfor a lower-level step-by-step ACME transaction. -
examples/ring_jetty.cljfor auto-renewing HTTPS withring-jetty-adapter.
These examples use Pebble for local ACME testing.
Security
See Security for security reporting and policy links.
License
Copyright © 2025-2026 Casey Link
Distributed under the EUPL-1.2.
Some files included in this project are from third-party sources and retain their original licenses as indicated in NOTICE.
Special thanks to Michiel Borkent (@borkdude) for the use of babashka/http-client and babashka/json.