Restricting API Access with API Keys

You can use API keys to restrict access to specific API methods or all methods in an API. This page describes how to restrict API access to those clients that have an API key and also shows how to create an API key.

For more information about API keys, see Why and When to Use API keys

Restricting or granting access to all API methods

By default in gRPC services, all API methods require an API key to access them. This means that all requests are rejected unless they have a key generated in your project or in project of a developer who shares your API.

To specify that an API key is not required to access your API:

  1. Open your project's gRPC API Configuration file in a text editor and find or add a usage section:

  2. In your usage section, specify an allow_unregistered_calls rule as follows. The wildcard "*" in the selector means that the rule applies to all methods in the API. You can find out more about selectors in Configuring a gRPC API Service.

    usage:
      rules:
      # All methods can be called without an API Key.
      - selector: "*"
        allow_unregistered_calls: true
    

Removing API key restriction for a method

To turn off API key validation for a particular method even when you've restricted API access for the API:

  1. Open your project's gRPC API Configuration file in a text editor and find or add a usage section:

  2. In your usage section, specify an allow_unregistered_calls rule as follows. The selector means that the rule applies just to the specified method - in this case, ListShelves. You can find out more about selectors in Configuring a gRPC API Service.

    usage:
      rules:
      # ListShelves method can be called without an API Key.
      - selector: endpoints.examples.bookstore.Bookstore.ListShelves
        allow_unregistered_calls: true
    

Calling an API using an API Key

Calling an API varies depending on whether you call from a gRPC client or an HTTP client.

gRPC clients

If a method requires an API key, gRPC clients need to pass the key value as x-api-key metadata with their method call. Select a tab below to see an example of how to do this when calling the Bookstore in Python, Java, Go, or Node.js:

Python

def run(host, port, api_key, auth_token, timeout):
    """Makes a basic ListShelves call against a gRPC Bookstore server."""

    channel = grpc.insecure_channel('{}:{}'.format(host, port))

    stub = bookstore_pb2.BookstoreStub(channel)
    metadata = []
    if api_key:
        metadata.append(('x-api-key', api_key))
    if auth_token:
        metadata.append(('authorization', 'Bearer ' + auth_token))
    shelves = stub.ListShelves(empty_pb2.Empty(), timeout, metadata=metadata)
    print('ListShelves: {}'.format(shelves))

Java

private static final class Interceptor implements ClientInterceptor {
  private final String apiKey;
  private final String authToken;

  private static Logger LOGGER = Logger.getLogger("InfoLogging");

  private static Metadata.Key<String> API_KEY_HEADER =
      Metadata.Key.of("x-api-key", Metadata.ASCII_STRING_MARSHALLER);
  private static Metadata.Key<String> AUTHORIZATION_HEADER =
      Metadata.Key.of("authorization", Metadata.ASCII_STRING_MARSHALLER);

  public Interceptor(String apiKey, String authToken) {
    this.apiKey = apiKey;
    this.authToken = authToken;
  }

  @Override
  public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
      MethodDescriptor<ReqT,RespT> method, CallOptions callOptions, Channel next) {
    LOGGER.info("Intercepted " + method.getFullMethodName());
    ClientCall<ReqT, RespT> call = next.newCall(method, callOptions);

    call = new ForwardingClientCall.SimpleForwardingClientCall<ReqT, RespT>(call) {
      @Override
      public void start(Listener<RespT> responseListener, Metadata headers) {
        if (apiKey != null && !apiKey.isEmpty()) {
          LOGGER.info("Attaching API Key: " + apiKey);
          headers.put(API_KEY_HEADER, apiKey);
        }
        if (authToken != null && !authToken.isEmpty()) {
          System.out.println("Attaching auth token");
          headers.put(AUTHORIZATION_HEADER, "Bearer " + authToken);
        }
        super.start(responseListener, headers);
      }
    };
    return call;
  }
}

Go

func main() {
	flag.Parse()

	// Set up a connection to the server.
	conn, err := grpc.Dial(*addr, grpc.WithInsecure())
	if err != nil {
		log.Fatalf("did not connect: %v", err)
	}
	defer conn.Close()
	c := pb.NewGreeterClient(conn)

	ctx := context.Background()
	ctx = metadata.NewOutgoingContext(ctx, metadata.Pairs("x-api-key", *key))

	// Contact the server and print out its response.
	name := defaultName
	if len(flag.Args()) > 0 {
		name = flag.Arg(0)
	}
	r, err := c.SayHello(ctx, &pb.HelloRequest{Name: name})
	if err != nil {
		log.Fatalf("could not greet: %v", err)
	}
	log.Printf("Greeting: %s", r.Message)
}

Node.js

function makeGrpcRequest (JWT_AUTH_TOKEN, API_KEY, HOST, GREETEE) {
  // Uncomment these lines to set their values
  // const JWT_AUTH_TOKEN = 'YOUR_JWT_AUTH_TOKEN';
  // const API_KEY = 'YOUR_API_KEY';
  // const HOST = 'localhost:50051'; // The IP address of your endpoints host
  // const GREETEE = 'world';

  // Import required libraries
  const grpc = require('grpc');
  const path = require('path');

  // Load protobuf spec for an example API
  const PROTO_PATH = path.join(__dirname, '/protos/helloworld.proto');
  const protoObj = grpc.load(PROTO_PATH).helloworld;

  // Create a client for the protobuf spec
  const client = new protoObj.Greeter(HOST, grpc.credentials.createInsecure());

  // Build gRPC request
  const metadata = new grpc.Metadata();
  if (API_KEY) {
    metadata.add('x-api-key', API_KEY);
  } else if (JWT_AUTH_TOKEN) {
    metadata.add('authorization', `Bearer ${JWT_AUTH_TOKEN}`);
  }

  // Execute gRPC request
  client.sayHello({ name: GREETEE }, metadata, (err, response) => {
    if (err) {
      console.error(err);
    }

    if (response) {
      console.log(response.message);
    }
  });
}

HTTP clients

If you are using gRPC for Endpoints' HTTP transcoding feature, HTTP clients can send the key as a query parameter in the same way they do for OpenAPI services.

Sharing APIs protected by API key

You can share your API with other developers so they can enable the API on their own cloud project and generate their own API key for use in calling your API. For more information, see Sharing an API.

Creating an API key

If you use API key protection for your API, clients need to provide a valid API key when calling the API. You can provide clients with a valid API key generated within your project, or optionally, if you share your API with developers, those developers can also generate a valid API key.

  1. Create a server API key.

    Go to the Create server API key page.

  2. Give the key to developers who want to call your API.

Further reading

For background information about Api keys and how they differ from user authentication, see When and Why to use Api Keys.

Monitor your resources on the go

Get the Google Cloud Console app to help you manage your projects.

Send feedback about...

Cloud Endpoints with gRPC