I’m trying to automate the creation of Wireguard profiles to connect to various Proton VPN servers. As far as I can tell, when you generate one online through account.proton.me:

  • The client generates a private key in-browser.
  • Client POSTs the corresponding public key, along with the chosen server and some other parameters, to /api/vpn/v1/certificate.
  • Server registers the given public key and returns the parameters that should be used to construct the config file.
  • Client combines returned parameters with the private key to create the final config file.

I am attempting to replicate this process with a key generated using wg:

wg genkey | tee privkey.key | wg pubkey > pubkey.key

However when sending this pubkey to the server (leaving everything else exactly as captured from a working in-browser request), it responds with:

{
  "Code": 2001,
  "Error": "Unable to read the key, please provide a valid EC key",
  "Details": {}
}

Replacing my custom pubkey with a pre-existing pubkey from a config generated through the Web UI instead returns ClientPublicKey fingerprint conflict, please regenerate a new key, so I don’t think I’m messing up the request format.

My questions are:

  • Is there a better/more official way to do this? I couldn’t find anything searching.
  • Why does this not work? Surely wg creates valid EC keys? Does Proton have some additional constraints on valid keys for some reason?

I don’t have much (or really any) experience with WireGuard, so perhaps I’m missing something obvious? Any help would be appreciated.