Site Color

Text Color

Ad Color

Text Color





Sign Up to Save Your Colors


How to Pin Mobile gRPC Connections by@skiph

How to Pin Mobile gRPC Connections

Skip Hovsmith Hacker Noon profile picture

Skip Hovsmith

Developer and Advocate — Software Performance and API Security

Last-mile Security for gRPC-connected mobile APIs

In Consider gRPC for Mobile APIs, we evaluated gRPC for use in mobile applications. We took a look at common operations such as:

A basic request-response API callToken-based authenticationA single request, streaming response API call

I concluded that the RPC function call paradigm felt more natural to me than designing and implementing a fully-RESTful API implementation, and I said I wouldn’t hesitate to use gRPC with mobile clients when the API is static and well understood.

For mobile apps, certificate pinning is an important capability to strengthen API security, and in this sequel, we’ll examine certificate pinning for gRPC on Android. Spoiler alert — in the end, it’s quite similar to pinning a restful connection.

Certificate Pinning

Transport Layer Security (TLS) is a well accepted and evolving standard to strengthen privacy and message integrity. When establishing a connection, a server endpoint sends its public key certificate to the requesting client. The client follows the certificate chain of trust until it reaches a root certificate it implicitly trusts.


(Source: Wikipedia — chain of trust: image originally via Gary Stevens of

Android and iOS devices maintain an installed set of certificates which they implicitly trust. Unfortunately, it is too easy to trick mobile devices into trusting certificates signed by unexpected certificate authorities. Diagnostic tools, such as mitmproxy, use this same technique to intercept and potentially interfere with encrypted HTTPS streams.

On mobile devices, certificate pinning should be used to limit trust to website leaf certificates or only those intermediate or root authorities trusted by the app itself. You can pin against the certificates, their public keys, or hashes of their public keys. Options for storing these certificate or key pins include:

  • Preloading: Embedding the pins inside the distributed app package is usually the easiest to implement. Upgrading the pin set, though, requires an app field upgrade, so it is recommended to install multiple leaf and intermediate pins with each release.
  • Trust on First Use (TOFU): endpoints’ public keys are determined on first use after installation or upgrade. Security depends on the security of the environment at first use.
  • Pin Server: Request pins from a trusted server. How to you trust the pin server? Perhaps you pin the pin server! If the pin server is stable, this allows you to manage a dynamic set of endpoints without requiring application upgrades for each change of served pins. Upgrades are only required if the pin server’s certificates change. It’s an interesting trade off and the subject of a future post.

When verifying the pinning certificates, the client verifies both the certificate’s signature and the requested hostname. Because the same IP address may share multiple hostnames, Server Name Indication is a TLS extension which enables a client to request a specific certificate by virtual hostname. In addition to its use in virtual hosting, this technique simplifies debugging self-signed certificates served from localhost.

Pinning gRPC Managed Channels

With gRPC, a client makes an rpc call to a stub interface which, through a channel, sends one or more proto request messages to and receives one or more response messages from the server. In Consider gRPC for Mobile APIs, we used a plain managed channel for our transport. To pin the channel, we will enable TLS (SSL) and create our own set of trusted certificates, separate from the certificates already installed on the device. We’ll use Android for our examples.

First, we will build our own keystore within our demonstration app. For convenience, we store a set of public key certificates as raw resources, and we identify those resources in a certs.xml resource file:

<?xml version="1.0" encoding="utf-8"?>

   <integer-array name="certs">


The keystore is created when the ShapesActivity is started, and the keystore and a server name override are passed to our pinned managed channel, PinnedChannelBuilder:

// build a key store from a set of raw certificates
KeyStore createPinnedKeyStore(int certsId) {
  TypedArray rawCerts = null;
  KeyStore ks = null;

  try {
    rawCerts = getResources().obtainTypedArray(certsId);

    ks = KeyStore.getInstance(KeyStore.getDefaultType());
    ks.load(null, null);
    CertificateFactory cf = CertificateFactory.getInstance("X.509");

    for (int i = 0; i < rawCerts.length(); ++i) {
      InputStream certIS = getResources().
          openRawResource(rawCerts.getResourceId(i, -1));
      X509Certificate cert = (X509Certificate) cf.generateCertificate(certIS);
      ks.setCertificateEntry("cert" + i, cert);
  } catch (Exception e) {
    throw new RuntimeException(e);
  } finally {
    if (rawCerts != null) rawCerts.recycle();
  return ks;

protected void onCreate(Bundle savedInstanceState) {
  // ...

  // open grpc managed channel

  String host = getResources().getString(;
  int port = getResources().getInteger(R.integer.port);
  String serverHostOverride = "localhost";
  KeyStore certsKS = createPinnedKeyStore(R.array.certs);

  channel =, port, 
      serverHostOverride, certsKS);

We override the server name so that the server will respond with an end-entity certificate whose common name (CN) matches what we have pinned.

The PinnedChannelBuilder we are building will use a customized SSLSocketFactory to make its connections. Java’s security and networking stack make this a bit tedious, requiring 1) building a containing our, 2) creating a containing this TrustManagerFactory, and 3) exposing the from within the SSLContext:

public class PinnedChannelBuilder {
  public static ManagedChannel build(String host, int port,
          @Nullable String serverHostOverride,
          KeyStore certsKS) {
    ManagedChannelBuilder<?> channelBuilder = 
        ManagedChannelBuilder.forAddress(host, port)
            .maxInboundMessageSize(16 * 1024 * 1024);
    if (serverHostOverride != null) {
      // Force the hostname to match the cert the server uses.
    try {
      ((OkHttpChannelBuilder) channelBuilder).useTransportSecurity();
      ((OkHttpChannelBuilder) channelBuilder).
    } catch (Exception e) {
      throw new RuntimeException(e);

  private static SSLSocketFactory getSslSocketFactory(KeyStore certsKS)
          throws Exception {
    if (certsKS == null) 
        throw new RuntimeException("No pinning Certificates found");

    // initialize trust manager factor from certs keystore

    TrustManagerFactory tmf = TrustManagerFactory.

    // initialize SSL context from trust manager factory

    SSLContext context = SSLContext.getInstance("TLS");
    context.init(null, tmf.getTrustManagers() , null);

    // return socket factory from the SSL context

    return context.getSocketFactory();

Though cumbersome, this is not much different than building a custom socket factory for a restful HTTPS connection, although many networking stacks and Android N have convenience methods to hide this complexity.

Trying It Out

To try it out, we use the same shapes demo application we used previously. We are running a gRPC server on localhost serving a shapes.proto API to a shapes app running in a local Android emulator.


First, we’ll generate a self-signed private key, public-key certificate pair for localhost using openssl:

$ openssl req -newkey rsa:4096 -nodes -keyout localhost.key 
    -x509 -days 365 -out localhost.crt

Generating a 4096 bit RSA private key
writing new private key to 'localhost.key'
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
Country Name (2 letter code) []:
State or Province Name (full name) []:
Locality Name (eg, city) []:
Organization Name (eg, company) []:
Organizational Unit Name (eg, section) []:
Common Name (eg, fully qualified host name) []:localhost
Email Address []:


The localhost.crt certificate file should be copied into the shape app’s raw resources directory (app/src/main/res/raw/). Similarly, we generate an otherhost.crt certificate file and also copy it to the raw resource directory.

We’ll install both the localhost.key private key and the localhost.crt certificate files into our gRPC server. gRPC servers are commonly configured for mutual-SSL. Our client is pinning the gRPC server and not the other way around, so ensure mutual SSL is disabled.

Now we fire up the app. The managed channel requests the localhost certificate from the server, and the channel is successfully pinned upon connection. Hitting the Stream button, we see the expected response:


To test the pinning, we delete the localhost certificate from the app and restart. This time the server delivers the localhost certificate, but the trust manager finds no matching pinned certificate, so the channel connection fails:


To keep it simple, we have only shown self-signed leaf certificates. A better practice would be to pin on intermediate certificates. Square’s certstrap tool is an excellent resource for generating your own test certificate authority and longer key chains if you would like to explore these scenarios.

Wrapping Up

On Android, we were able to demonstrate a pinned gRPC channel, and it really wasn’t any more difficult than pinning a restful HTTPS connection. Including Consider gRPC for Mobile APIs, we have demonstrated:

  • A basic request-response API call
  • Token-based authentication
  • A single request, streaming response API call
  • Pinned TLS connections to the server

gRPC’s function call paradigm, along with gRPC’s ability to generate both client and server API interfaces for many target languages from a single proto file and our demonstration of basic and secure API functionality, makes gRPC a reasonable approach for mobile API development.