Consider we implement remote service, which will be accessible via API(i.e. restful http or grpc). All users are authenticated via pgp keys and each user has pgp keypair.

How to implement authentication for such a service?

I see multiple approaches and I'm unsure which one to choose:

  1. Convert keypair to X509 certificate, use TLS certificate authentication (1, 2) to authenticate users. Requires some fiddling on client side, also unclear how to convert.
  2. Require users to sign timestamp on each request. Check that timestamp is close to current server time. Unclear if this approach is secure.
  3. Give users expirable tokens, which are either stored in DB or have MAC, require users to attach token signatures.
  4. Some better approach I cant think of
  • 1
    $\begingroup$ Sent an ad-hoc login token PGP encrypted. $\endgroup$ – eckes May 2 '17 at 1:16
  • $\begingroup$ @eckes currently implemented with pgp-encrypted jwt tokens $\endgroup$ – sashab May 5 '17 at 14:37
  • $\begingroup$ yeah I mean more interactively, as it requires no special software on the client $\endgroup$ – eckes May 5 '17 at 14:38
  1. Sign a self-signed X.509 certificate using PGP signature generation.

Let the web user create a self-signed X.509 certificate and store the certificate and private key in a PKCS#12 key store. Then create a PGP signed container with this certificate included. Let the web server put it in a trust store after verifying & stripping the PGP signature. The client needs to configure the PKCS#12 soft token with the browser used (or the Windows store, if IE / Edge / another SChannel based browser is used).

You would need to provide guidance to the users on how to create the self signed certificate and how to put the self signed certificate and private key store in the local key store of the browser. You could also create an application to do this for the users.


PGP is not ideal for web service authentication because the authentication would involve the server issuing a challenge and the client returning a signed response. Now how will the user provide the signed response (I understand from your question that the client is a browser)? Your options are:

  1. Provide a UI on the web page with some Javascript library that takes the private key and signs the response. This approach should be objected by users because it is typically not safe to load your private key to a web page.

  2. Copy the unsigned response from the browser to another client, sign it, and then copy the signed response to the browser. This approach will surely be objected by users who will hate you for making a service with bad usability.

So if you have any other choice you're probably better off not using PGP. If you must use PGP then the first option is probably the only one that will actually work. That's similar, for example, to the way the AWS management console works, although in their case they don't use the keys for authentication. One rather calls their web services with an equivalent of a username + the request parameters, and signs the message with their private key.

So if you have the flexibility perhaps you could skip the challenge part by issuing the user a "username"; this could be for example a hash of the PGP public key. The user would then send the username as one of the service arguments and then sign the message, similar to how AWS works. The server then authenticates the user by retrieving the public key based on the username, and using the public key to validate the signature. Note that this method still requires the user to load the private key to the browser.

  • $\begingroup$ Sorry, I did not make it clear: service would be consumed not from browsers, but from native applications, the task is to make API for them. I've edited the question to make it clear. $\endgroup$ – sashab May 3 '17 at 10:58
  • $\begingroup$ @sashab So it is unclear what you mean in "Requires some fiddling on client side", you'd need to fiddle with the client side with any form of authentication. In addition, even with a REST API I believe it is better to streamline the authentication with some "username". It is very likely you'll anyhow need this username going forward, e.g. to associate with access rights, account expiration, etc. $\endgroup$ – avnr May 3 '17 at 15:10
  • $\begingroup$ by "fiddling" I mean that converting pgp key to x509 cert is not a commonly done operation, hence low support in libraries and it would require programmer to dig into internals of crypto packages. You are absolutely right about usernames, it is planned to use them here. $\endgroup$ – sashab May 3 '17 at 22:19

Another approach - not sure if it would be compatible with an API, but it has been successfully implemeted on certain sites within the more shadowy recesses of the internet. Register each user with a PGP pubkey that they created and to which they control the privkey. Upon entering a username for login, serve a PGP-encrypted message containing a single-use login token using the pubkey registered to that user. User decrypts the message locally on their own machine and enters the token string back into the login page. Can be done simply and easily in PHP and requires no javascript to run.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.