Storing certificates more securely when using Google APIs, OAuth 2.0 and .Net

Recently, I’ve been replacing bit.ly with the Google URL shortener service for a .Net project. It’s a pretty simple service, and the documentation shows very clearly how to get going.

Google have 3 different ways of authenticating using OAuth 2.0 (details), the method I am using is as a “Service Account”. Their code sample is thus:

String serviceAccountEmail = "SERVICE_ACCOUNT_EMAIL_HERE";
var certificate = new X509Certificate2(@"key.p12", "notasecret", X509KeyStorageFlags.Exportable);

ServiceAccountCredential credential = new ServiceAccountCredential(
  new ServiceAccountCredential.Initializer(serviceAccountEmail)
  {
    Scopes = new[] { PlusService.Scope.PlusMe }
  }.FromCertificate(certificate));

// Create the service.
var service = new UrlshortenerService(new BaseClientService.Initializer()
{
  HttpClientInitializer = credential,
  ApplicationName = "API Sample",
});

The key thing that I want to draw your attention to is line 2, this implies (to me) that you are probably goign to keep the certificate in source control along with your code. This isn’t good, as it could lead quite easily to mistakenly making it public (e.g. pushing the project to GitHub).

A better solution would be to attempt to load the certificate from the local certificate store on the machine.

So that means that line 2 above, would be replaced with the following:

string certificateIssuerName = "blahblahblah123456.apps.googleusercontent.com";

X509Store store = new X509Store(StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
var cert = store.Certificates.Find(X509FindType.FindByIssuerName, certificateIssuerName, false)[0];
store.Close();

Things to know:

  1. NB: Very important, you need to make sure you call the Open method on the store, otherwise you will find that calling the Find method will never return you a certificate.
  2. When importing the certificate into your certificate store, make sure you include the private key, otherwise your code won’t work.
Advertisements

6 thoughts on “Storing certificates more securely when using Google APIs, OAuth 2.0 and .Net

  1. Tony says:

    Hi, You mention that when exporting the certificate into your certificate store, make sure you include the private key. How do you do that? I am only able to add the certificate but cant add the private key.

    var newcertificate = new X509Certificate2(“key.p12”, “notasecret”, X509KeyStorageFlags.Exportable);

    var newstore = new X509Store(StoreName.My, StoreLocation.LocalMachine);
    newstore.Open(OpenFlags.ReadWrite);
    newstore.Add(newcertificate);
    newstore.Close();

    Thanks

      • Tony says:

        Hi Ken, thanks for replying. Do you have any links to documents on how to do this import. I try importing the cert via the wizard but for some reason it’s not added. Only when I run the code does it add it to the store.

        Thanks

      • Tony says:

        Ken, never mind, the reason the MMC didn’t work was that I had imported the cert via code first and it created a conflict. I was able to import the certificate and bring it in with the key. everything works fine. Thank you so much for pointing me in the right direction and for the great article.

        I appreciate your help, take care!

  2. Nick says:

    Hi. Thanks for posting this article. I was skirting around this solution but this cleared it all up. Unfortunately I’m having some real problems moving from the old Google APIs to V3. We originally had the old version installed in the GAC for use with SSIS but as these DLLs are not signed, I’m unable to do that. So I moved the code into a Web Service wrapper and it works fine in with my unit tests. However, when running the Web Service wrapper and accessing it via a GET request, comms just breat down and the code hangs when requesting back a list of accounts. BUT that’s not my question… So I have installed my certificate into the Cert Store along with the private key. It’s telling me everything is perfect in MMC. However, I get the certificate fine and can see its properties in debug on VS BUT when I then attempt to use it with the ServiceAccountCredential object I get a “Key not in a valid state” Exception thrown. The ServiceAccountCredential object was initialised fine when I was referencing the certificate using just the file path before :-/

    Thanks

    • KenR says:

      Hi Nick, I haven’t had a chance to look into this yet, is there any more detail in the exception message? I’ll try and find some time to look into this next week. Ken

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s