Most secrets managers authenticate a machine by handing it a token and then trusting whoever sends that token back. The token is a string. If it leaks out of an environment variable, a log line, a crash dump, or the manager's own database, anyone holding the string can read the same secrets that machine could read, from any IP, until someone notices and rotates it. That has been the default in secrets storage for a long time, and it has a few problems we weren't willing to ship.
So SikkerKey does machine authentication differently. Every secret read is an asymmetric signed request. Here is what that buys you, and why it holds up better than a bearer token when something goes wrong.
What a bearer token actually proves
A bearer token proves exactly one thing: the sender has the token. It says nothing about what is on the other end of the connection. The name is honest. The bearer is authenticated, whoever the bearer happens to be.
That has two consequences people tend to gloss over. The client holds a reusable secret it can leak, and the server holds a copy it can leak too. The credential stays valid for its whole lifetime against every endpoint it is scoped to. Capture it once and you have a working key until expiry or rotation, whichever comes first.
How SikkerKey signs each request
Every machine gets an Ed25519 keypair when it enrolls. The private key stays on the machine and never touches the network. We store only the 32-byte public key.
To read a secret, the machine signs a short string that describes the exact request it is making:
{method}:{path}:{timestamp}:{nonce}:{bodyHash}
bodyHash is the SHA-256 of the request body. The signature travels in headers alongside the machine id, the timestamp, and a nonce (X-Signature, X-Machine-Id, X-Timestamp, X-Nonce). We rebuild that same string from the request we actually received and verify the signature against the machine's public key.
Because the signature covers the method, the path, and a hash of the body, a captured signature can't be repointed at a different endpoint or replayed against a tampered body. We also reject query strings on these routes, because the signed path doesn't include them and we don't want a valid signature for /v1/secrets to ride along with /v1/secrets?owner=someone-else.
There is no shared secret in this exchange. The machine proves possession of a private key without ever sending it.
Audit logs that name a machine
This is the part that quietly changes how you operate. With machine authentication backed by signatures, every read is provably from one keypair, and that keypair belongs to one machine with a name, a vault, and an owner.
So an audit entry can say "machine prod-api-7 read DATABASE_URL at 14:02 from 10.0.3.4" and actually mean it. The honest version of that log line under bearer tokens is "someone holding token abc123 read DATABASE_URL," and abc123 might be the machine, a teammate who copied it into their shell, or whoever scraped it out of a log aggregator. You can attach an audit record to a real identity instead of a string of characters, which is the difference between an audit trail you can act on and one you can only squint at.
Replay protection by construction
A bearer token has no replay protection of its own. Capture one valid request and you can send it again, or a thousand times.
SikkerKey rejects replays two ways. The timestamp has to land within five minutes of our clock, so a stale capture is dead on arrival. And the nonce has to be unique per machine. We record every nonce we accept and refuse a repeat, so the same signed request never works a second time. The nonce check runs only after the signature verifies, so a forged request is rejected before it ever reaches that step.
You get replay protection as a property of the protocol, without having to bolt on short token lifetimes and hope rotation outruns the attacker.
The credential is only alive for one request
This is the part I care about most.
A bearer token is a standing credential. It sits in memory or on disk being valid the entire time, waiting to be copied. A signature authorizes a single operation: this method, this path, this body, at this moment. Nothing durable is in flight that grants ongoing access.
Even if someone intercepts a request on the wire, the nonce is already spent and the timestamp expires within minutes. The blast radius of a captured request is that one request, which has already happened. There is no leftover key to reuse.
The credential store isn't the prize
Here is where asymmetric keys pay off the most. With bearer tokens, the place that holds authentication material holds the credentials themselves, or the secrets used to verify and mint them. Whatever sits there is replayable. Get a copy and you can authenticate as the clients it covers.
A signed-request model keeps public keys. A public key can verify a signature. It cannot produce one. Nothing in the authentication layer lets you impersonate a machine, because the part that does the authenticating, the private key, only ever lives on the machine. We don't hold it, so we can't lose it.
Where this leaves you
None of this is exotic cryptography. It is Ed25519 signatures, a timestamp, and a nonce, assembled so that the credential never outlives the request it was made for. The interesting part is what you stop carrying around: a long-lived string that is functionally equal to the secrets sitting behind it.
If you're weighing secrets management options for a fleet of machines, run one test in your head. Picture a single secret leaking into a log line. With bearer tokens, that can cost you everything the token could read, for as long as it stays valid. With signed requests, it costs you a request that already finished.