Inter-Service Authentication with SSL

At Collective Idea, we love building web services. Oftentimes we also build the client applications that consume those services.

One of the major challenges with a service-oriented architecture is authenticating communication between the client and the service as well as between services.

Oh, You Mean OAuth!

OAuth is a good candidate for this type of authentication. It provides flexibility in terms of scoped authorization levels, securely signed requests, token expiration and all sorts of other goodies. And these things are great, especially for public-facing applications, where anybody could register through your OAuth provider.

But if you're only dealing with a small number of controlled, trusted clients, implementing an OAuth provider for each service might be a bit much.

Then What?

Every request to the services needs to identify its client application and more importantly, it needs to be verified. What we need is a tried and tested way to communicate trust.

Enter: SSL

We usually see SSL in the form of an "https://" URL in our browser, and a little lock icon to make us feel all warm and fuzzy. That feeling of security comes from the fact that our browser has identified the website and we can trust that they actually are who they say they are.

This sounds awfully close to what we're looking for. If an SSL certificate can verify the recipient of a request, we should be able to reverse the process to verify the sender of a request.

SSL Authentication

To set up our SSL authentication, each client application needs its own SSL certificate. So first thing's first: we need a private key with which to sign all of these SSL certificates… one key to rule them all. Signing all of the client certificates with the same private key will allow us to verify their authenticity later.

openssl genrsa -out master.key 1024

Now that we have our master key, we can start generating SSL certificates. Each certificate will require a new CSR (certificate signing request). CSR generation will prompt for information about the certificate and we'll take that opportunity to identify the client application that this certificate belongs to.

# Enter "web-client" for "Organizational Unit Name."
# The remaining attributes aren't important.
openssl req -new -key master.key -out web-client.csr

With the CSR in hand, generating a signed certificate is easy.

openssl x509 -req -in web-client.csr -signkey master.key -out web-client.crt

This certificate is given to the client application and every request originating from the client will include the contents of that certificate in a custom header.

Meanwhile, in the service… when a request is received we'll need to assert that the certificate provided is authentic. We do this by verifying that the certificate is signed by the master key. The best part is that the service doesn't even need the private, master key to do that verification. It can use a public key derived from the master key instead.

openssl rsa -in master.key -pubout >

Every service gets this same public, master key and uses it to verify all incoming requests.

Finally, Ruby

Assuming your service is written in Rails, here's how that verification might be implemented:

class ApplicationController < ActionController::Base
  before_filter :require_authentication


  def require_authentication
    unless current_certificate.verify(public_key)
      head :forbidden

  def public_key
    @public_key ||=['AUTH_PUBLIC_KEY'])

  def current_certificate
    @current_certificate ||=['X-SSL-Auth'])

  def current_client

The public key used for verification is kept in the server's environment at ENV\['AUTH\_PUBLIC\_KEY'\] and the current request's certificate is pulled from the headers.

The certificate responds to the verify method which accepts the public key and simply returns true if the certificate is authentic or false otherwise.

You'll notice the current\_client method as well, which extracts the organizational unit from the certificate that we set during the CSR generation. This identifies the client application making the request. With that information, the service can implement any sort of access controls that may (or may not) be required.

In the Wild

At Collective Idea, we think SSL certificate authentication is a cool idea and in some cases, a great fit. It's also comforting to know that Square uses this same approach for authentication between its own services.

In fact, this post was inspired by a talk by Square's Chris Hunt at RubyConf 2012. His talk omits some of the details of certificate generation and verification but it's a fantastic resource for good service-oriented architecture.

Computer Security - Protect Data - Computers by Perspecsys Photos is licensed under by CC BY-SA 2.0

Photo of Steve Richert

Steve is a Michigan State grad in mechanical engineering, but has been programming since he was in single digits with his Commodore 64. QBasic greatness followed.

After putting in his time with PHP, Steve discovered Ruby, Rails, Git and Agile development. Open source greatness followed. After long admiring their work, Steve can finally cross working for Collective Idea off his bucket list.

Steve lives in Grandville with his wonderful wife, Catie and son, Charlie.


Post a Comment

(optional — will be included as a link.)
  1. Interesting, thanks for writing this up.

    You don’t show how the client code is configured to send the cert with its requests.

    Also – how do you feel this approach compares to using “normal” server-side ssl + basic auth with a huge password? In both cases there is a secret that can be stolen and used by a malicious party just as easily (client cert vs. client password) so AFAIK the cert approach is not more secure. But maybe I’m missing something.

    December 17, 2012 at 17:12 PM
  2. John, with basic authentication, the service must be aware of which usernames and passwords are valid. One advantage of SSL certificates is that an (effectively) unlimited number of valid certificates can be issued to trusted clients with no code changes to the services.

    But you’re right to say that the advantage is not in the certificate’s security as much as its verifiability.

    December 17, 2012 at 21:04 PM
  3. Hi Steve,

    If you plan on using certificates to do the authentication, you might as well opt for Client-Side Authentication straight in the webserver. You could configure the Apache/Nginx webserver to only accept certain client-side certificates  which have been issued by a given Certificate Authority by utilizing a so-called Certificate Chain. In that way, you don’t need any Ruby verification code in your application layer. Instead, you shift the verification to the webserver and require that client applications provide a private key and associated certificate when authenticating. You don’t need custom headers for that

    Michel Barbosa
    December 17, 2012 at 21:11 PM
  4. Michel, that sounds pretty great. I’m no good at web server administration so the concept of sending a client-side certificate with the request is news to me. To clarify, the client would need to send the private key as well? Seems odd.

    December 17, 2012 at 21:16 PM
  5. Well, actually, the client application’s private key is used to setup a shared secret as part of the so-called SSL handshake between the client and the server. The client application’s private key is never transmitted to the webserver in plaintext, it’s just used to establish a shared secret after which data to and from the webserver is encrypted for the duration of the SSL session (which can be configured server side as well).

    If you rely on Client-Side authentication in the webservers AND you make sure to issue unique certificates for each client application AND you make sure that the client applications securely store their private key, you can instruct the webserver to forward the client-side certificate to the application layer through the request headers. In that case, you can use the client-side X509 certificate as a lookup key inside your Rails application for identiying a certain application. Alternatively, you can issue certificates which already contain details of the certificate owner, such as the name or FQDN of a certain client application.

    EIther way, by using client-side authentication in the webserver, you don’t need any custom Ruby certificate validation :)


    Michel Barbosa
    December 17, 2012 at 21:39 PM
  6. @Michel,

    Thanks for you post on Client-side authentication. Do you know of any good step-by-step tutorials for implementing this? Preferably nginx-centric? Thanks, ~Ben
    December 18, 2012 at 16:05 PM
  7. First one that came up:
    Carson Reinke
    December 18, 2012 at 18:47 PM
  8. Great post! Thanks.
    Kaleem Ullah
    January 10, 2013 at 11:35 AM
  9. Nice article, but is there a way of using a client public key on the servers instead of using the in all servers to verify the certificates?

    I’m thinking in something similar to what SSH does to authenticate or encrypt/decrypt the data. 

    This would enforce the clients to register themselves if they want to use that service. Insstead of doing this programmatically using the OU. Thanks

    February 06, 2013 at 11:39 AM
  10. Luis, yes you could certainly do something like that. The difference is that in the scenario outlined above, we don’t want to enable open registration with the service. We want all connections to the service to be previously and actively authorized by the service.

    February 08, 2013 at 20:20 PM
  11. Just desire to say your article is as astounding. The clearness in your post is simply excellent and i can assume you are an expert on this subject. Fine with your permission allow me to grab your feed to keep up to date with forthcoming post. Thanks a million and please keep up the enjoyable work.

    July 06, 2015 at 19:09 PM