Example: Use Cloud Bigtable C++ client with various gRPC credential classes

Use gRPC Credential Classes with Cloud Bigtable C++ client

Before you begin

Set the Environment Variable

There are many ways to authenticate with Google Cloud Platform, here we use the GOOGLE_APPLICATION_CREDENTIALS environment variable to setup authentication based on a key file:

export GOOGLE_APPLICATION_CREDENTIALS="[PATH]"

where [PATH] is file path for JSON file that contains either user account or Service account key. Please refer this link for more details on Google Authentication.

Use Access Token Credentials

Acquire Access Token

Use gcloud to acquire an Access Token

The following code shows how to use access token to connect to an Admin API endpoint.

  [](std::string const& project_id, std::string const& instance_id,
     std::string const& access_token) {
    auto call_credentials = grpc::AccessTokenCredentials(access_token);
    auto channel_credentials =
        grpc::SslCredentials(grpc::SslCredentialsOptions());
    auto credentials = grpc::CompositeChannelCredentials(channel_credentials,
                                                         call_credentials);
    auto options = Options{}.set<GrpcCredentialOption>(credentials);

    cbta::BigtableTableAdminClient admin(
        cbta::MakeBigtableTableAdminConnection(options));

    google::bigtable::admin::v2::ListTablesRequest r;
    r.set_parent(cbt::InstanceName(project_id, instance_id));
    r.set_view(google::bigtable::admin::v2::Table::NAME_ONLY);
    auto tables = admin.ListTables(std::move(r));
    for (auto& table : tables) {
      if (!table) throw std::move(table).status();
    }
  }

Use Refresh Token Credentials

Sample code to connect to an Admin API endpoint

#include "google/cloud/bigtable/admin/bigtable_instance_admin_client.h"
#include "google/cloud/project.h"

int main(int argc, char* argv[]) try {
  namespace cbta = ::google::cloud::bigtable_admin;
  namespace gc = ::google::cloud;
  std::string const project_id = argv[1];
  grpc::string refresh_token = R"""({
      "client_id": "XXXXXX.apps.googleusercontent.com",
      "client_secret": "<actual secret here>",
      "refresh_token": "<actual token value here>",
      "type": "authorized_user"
  })""";
  auto call_credentials = grpc::GoogleRefreshTokenCredentials(refresh_token);
  auto channel_credentials =
      grpc::SslCredentials(grpc::SslCredentialsOptions());
  auto credentials =
      grpc::CompositeChannelCredentials(channel_credentials, call_credentials);
  auto client = cbta::BigtableInstanceAdminClient(
      cbta::MakeBigtableInstanceAdminConnection(
          gc::Options{}.set<gc::GrpcCredentialOption>(credentials)));
  auto instances = client.ListInstances(gc::Project(project_id).FullName()));
  return 0;
} catch (std::exception const& ex) {
  std::cerr << "Standard C++ exception raised: " << ex.what() << std::endl;
  return 1;
}

Use JWT Access Token Credentials

The following code shows how to use a JWT access token to connect to an Admin API endpoint.

  [](std::string const& project_id, std::string const& instance_id,
     std::string const& service_account_file_json) {
    std::ifstream stream(service_account_file_json);
    if (!stream.is_open()) {
      std::ostringstream os;
      os << "JWTAccessToken(" << service_account_file_json
         << "): cannot open upload file source";
      throw std::runtime_error(os.str());
    }
    std::string json_key(std::istreambuf_iterator<char>{stream}, {});

    auto call_credentials =
        grpc::ServiceAccountJWTAccessCredentials(json_key, 6000);
    auto channel_credentials =
        grpc::SslCredentials(grpc::SslCredentialsOptions());
    auto credentials = grpc::CompositeChannelCredentials(channel_credentials,
                                                         call_credentials);
    auto options = Options{}.set<GrpcCredentialOption>(credentials);

    cbta::BigtableTableAdminClient admin(
        cbta::MakeBigtableTableAdminConnection(options));

    google::bigtable::admin::v2::ListTablesRequest r;
    r.set_parent(cbt::InstanceName(project_id, instance_id));
    r.set_view(google::bigtable::admin::v2::Table::NAME_ONLY);
    auto tables = admin.ListTables(std::move(r));
    for (auto& table : tables) {
      if (!table) throw std::move(table).status();
    }
  }

Use Google Compute Engine Credentials

The following code shows how to use a GCE credentials to connect to an Admin API endpoint.

  [](std::string const& project_id, std::string const& instance_id) {
    auto call_credentials = grpc::GoogleComputeEngineCredentials();
    auto channel_credentials =
        grpc::SslCredentials(grpc::SslCredentialsOptions());
    auto credentials = grpc::CompositeChannelCredentials(channel_credentials,
                                                         call_credentials);
    auto options = Options{}.set<GrpcCredentialOption>(credentials);

    cbta::BigtableTableAdminClient admin(
        cbta::MakeBigtableTableAdminConnection(options));

    google::bigtable::admin::v2::ListTablesRequest r;
    r.set_parent(cbt::InstanceName(project_id, instance_id));
    r.set_view(google::bigtable::admin::v2::Table::NAME_ONLY);
    auto tables = admin.ListTables(std::move(r));
    for (auto& table : tables) {
      if (!table) throw std::move(table).status();
    }
  }

One may face "Request had insufficient authentication scopes." error while running above example. This might be due to disabled "Cloud API access scope" for Bigtable. This error can be removed by providing sufficient access as explained here.

Use of IAM Credentials

Check IAM Policy

  namespace cbt = ::google::cloud::bigtable;
  namespace cbta = ::google::cloud::bigtable_admin;
  using ::google::cloud::StatusOr;
  [](cbta::BigtableTableAdminClient admin, std::string const& project_id,
     std::string const& instance_id, std::string const& table_id) {
    std::string table_name = cbt::TableName(project_id, instance_id, table_id);
    StatusOr<google::iam::v1::Policy> policy = admin.GetIamPolicy(table_name);
    if (!policy) throw std::move(policy).status();
    std::cout << "The IAM Policy for " << table_id << " is\n"
              << policy->DebugString() << "\n";
  }

Set IAM Policy

  namespace cbt = ::google::cloud::bigtable;
  namespace cbta = ::google::cloud::bigtable_admin;
  using ::google::cloud::StatusOr;
  [](cbta::BigtableTableAdminClient admin, std::string const& project_id,
     std::string const& instance_id, std::string const& table_id,
     std::string const& role, std::string const& member) {
    std::string table_name = cbt::TableName(project_id, instance_id, table_id);
    StatusOr<google::iam::v1::Policy> current = admin.GetIamPolicy(table_name);
    if (!current) throw std::move(current).status();
    // This example adds the member to all existing bindings for that role. If
    // there are no such bindings, it adds a new one. This might not be what the
    // user wants, e.g. in case of conditional bindings.
    size_t num_added = 0;
    for (auto& binding : *current->mutable_bindings()) {
      if (binding.role() == role) {
        binding.add_members(member);
        ++num_added;
      }
    }
    if (num_added == 0) {
      *current->add_bindings() = cbt::IamBinding(role, {member});
    }
    StatusOr<google::iam::v1::Policy> policy =
        admin.SetIamPolicy(table_name, *current);
    if (!policy) throw std::move(policy).status();
    std::cout << "The IAM Policy for " << table_id << " is\n"
              << policy->DebugString() << "\n";
  }

Check IAM Permissions

  using ::google::cloud::StatusOr;
  namespace cbt = ::google::cloud::bigtable;
  namespace cbta = ::google::cloud::bigtable_admin;

  [](cbta::BigtableTableAdminClient admin, std::string const& project_id,
     std::string const& instance_id, std::string const& table_id,
     std::vector<std::string> const& permissions) {
    std::string table_name = cbt::TableName(project_id, instance_id, table_id);
    auto result = admin.TestIamPermissions(table_name, permissions);
    if (!result) throw std::move(result).status();
    std::cout << "The current user has the following permissions [";
    std::cout << absl::StrJoin(result->permissions(), ", ");
    std::cout << "]\n";
  }