A Padlock That Means Something
Half of what you build refuses to work over plain HTTP, and the usual fix — a self-signed certificate and a browser warning you click through — teaches you to ignore the warning that exists to protect you. There is a better answer, and it is one command.
The problem
Browsers have spent a decade moving features behind “secure context”. Over plain HTTP you lose:
- Service workers. No offline, no push, no PWA — they simply do not register.
-
Secure cookies.
SecureandSameSite=Nonecookies are dropped, which means sessions that behave one way locally and another in production. - Most OAuth providers. Many refuse to register a non-HTTPS callback at all, so “log in with…” cannot be tested locally.
- Clipboard, geolocation, camera, WebAuthn. All secure-context only.
And beyond the features: if you develop over HTTP and deploy over HTTPS, mixed-content bugs and protocol-relative URL mistakes are invisible until production. You are testing a different thing from the one you ship.
The hard way
The usual workaround is a self-signed certificate, which produces a full-page browser warning you click through several times a day. That is worse than it looks, for two reasons.
It trains the reflex. The interstitial exists to stop you proceeding to a site that is lying about who it is, and you are practising proceeding.
And it does not actually work for the things you wanted. A service worker will not register behind an untrusted certificate no matter how many times you dismiss the warning. Neither will an API client that validates certificates — so your app's own server-to-server calls fail in ways that have nothing to do with your code.
One command
grove secure freddy
✓ freddy is now served over HTTPS → https://freddy.test
A real padlock. No warning, no exception, no
curl -k. Your browser trusts it, your HTTP
client trusts it, your service worker registers.
What happened: grove init created a
certificate authority on your machine and added it to the
system trust store. grove secure issues a
certificate for that site, signed by it. Your system
trusts the CA, so it trusts the certificate. That is the
whole mechanism, and it is the same one the public web
uses — only the authority is yours.
Why a CA on your laptop is safe
A certificate authority your machine trusts is, in
principle, a dangerous thing: a CA can vouch for
any hostname. If Grove's CA could sign a
certificate for google.com, and your system
trusts Grove's CA, then anyone who got hold of that
key could impersonate Google to you.
So the CA carries a name constraint: it is
cryptographically limited to your TLD. A certificate it
signs for anything outside .test is rejected
by the verifier — not by Grove's politeness, but
by the same rules your browser applies to every certificate
on the internet. The worst a leaked key can do is
impersonate a name that only ever resolves to your own
machine.
That claim is not a promise in a document. It is a
regression test in Grove's own suite, run through the
same verifier browsers use: a Grove-signed certificate for
google.com is refused, the identical
certificate signed by an unconstrained CA is accepted
— proving the refusal is the constraint doing its job
and not an unrelated failure — and the certificates
Grove actually issues are accepted.
grove unsecure <site> reverses it if you
ever need the plain version.
What you learned
- Service workers, secure cookies, OAuth callbacks and WebAuthn need HTTPS — local development without it tests something you do not ship.
- Click-through warnings train the wrong reflex and still do not enable the features you wanted.
- grove secure issues a certificate from a CA your system already trusts.
- The CA is name-constrained to your TLD, enforced by the verifier rather than by good manners.
- Secure every site. Mixed protocols across a machine cost more than the command does.