CURLOPT_HTTPSIG_KEY(3)

πŸ“¦
version 8.23.0 Β· 3 versions
, in alpine 3.23, alpine 3.24

πŸ’… CURLOPT_HTTPSIG_KEY(3) β€” like, the libcurl manual, but make it make sense

okay bestie so real quick: this page lives in the Library Functions Manual and it's here to explain CURLOPT_HTTPSIG_KEY. yes, the name is a mouthful. no, we're not skipping it. 🫢


✨ NAME ✨

CURLOPT_HTTPSIG_KEY β€” the hex-encoded key for HTTP Message Signatures. that's it, that's the whole vibe. πŸ”‘


🌸 SYNOPSIS 🌸

#include <curl/curl.h>

CURLcode curl_easy_setopt(CURL *handle, CURLOPT_HTTPSIG_KEY, char *key);

πŸ¦‹ DESCRIPTION πŸ¦‹

πŸ§ͺ vibe check: this feature is experimental and may change before anyone decides it's actually stable. the docs literally advise against using it in production, so like… don't. fr fr.

So what you do is you pass a null-terminated string containing the hex-encoded private key or shared secret that you're using for RFC 9421 HTTP Message Signatures.

The deets by algorithm, because they're different, iykyk:

  • ed25519 πŸ’œ β€” this is the 32-byte private seed, which is 64 hex characters.
  • hmac-sha256 πŸŽ€ β€” this is the shared secret, as hex. the decoded length is half the number of hex digits, up to CURL_MAX_INPUT_LENGTH / 2 bytes. that's the same upper bound every other libcurl string option gets, no special treatment.

PEM and other encodings are not supported. you pass the raw key material as hex. that's the whole assignment. πŸ™ˆ

πŸ”₯ Generating Ed25519 keys

With OpenSSL 3:

openssl genpkey -algorithm ED25519 -out k.pem
openssl pkey -in k.pem -text -noout | \
  grep -A3 ^priv: | \
  tr -cd '[:xdigit:]' > k.hex

and then k.hex is literally one line of 64 hexadecimal digits. slay. ✨

Good news though β€” the application does not have to keep the string around after setting this option. so you can free your little buffer and not think about it again. 🧚

Also: using this option multiple times makes the last set string override the previous ones. classic. and set it to NULL to disable its use again. πŸ‘‘


πŸ’… DEFAULT πŸ’…

NULL

like, nothing. no key, no drama.


🌈 PROTOCOLS 🌈

This functionality affects http only. that's it. just http.


⭐ EXAMPLE ⭐

int main(void)
{
  CURL *curl = curl_easy_init();

  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/api");
    curl_easy_setopt(curl, CURLOPT_HTTPSIG_ALGORITHM, CURLHTTPSIG_ED25519);
    curl_easy_setopt(curl, CURLOPT_HTTPSIG_KEY,
                     "9f8362f87a484a954e6e740c5b4c0e84"
                     "229139a20aa8ab56ff66586f6a7d29c5");
    curl_easy_setopt(curl, CURLOPT_HTTPSIG_KEYID, "my-key-id");
    curl_easy_perform(curl);
  }
}

look at that. key set, algorithm set, key id set, request sent. main character energy. πŸ”₯


πŸŽ€ AVAILABILITY πŸŽ€

Added in curl 8.22.0. if your curl is older than that, this option simply does not exist yet, so don't come for me. 😭


πŸ’– RETURN VALUE πŸ’–

curl_easy_setopt(3) returns a CURLcode that tells you success or error.

CURLE_OK (0) means everything was OK. non-zero means an error happened β€” see libcurl-errors(3) for the full list. 🌸


🫢 SEE ALSO 🫢


k bye ily, go sign some messages responsibly πŸ¦‹

this page came to you from libcurl, dated 2026-10-25, in the CURLOPT_HTTPSIG_KEY(3) era of the Library Functions Manual. mwah πŸ’‹

πŸ“¦ where this page comes from