Zack Zack - 1 year ago 478
Java Question

How do I access request metadata for a java grpc service I am defining?

For some background, I am attempting to use grpc auth in order to provide security for some services I am defining.

Let's see if I can ask this is a way that makes sense. For my python code, it was pretty easy to implement the server side code.

class TestServiceServer(service_pb2.TestServiceServer):

def TestHello(self, request, context):

## credential metadata for the incoming request
metadata = context.invocation_metadata()

## authenticate the user using the metadata

So, as you can tell, I am able to get the metadata from "context" quite easily. What is harder for me is to do the same thing in java.

public class TestImpl extends TestServiceGrpc.TestServiceImplBase {

public void testHello(TestRequest req, StreamObserver<TestResponse> responseObserver) {

// How do I get access to similar request metadata here?

// from the parameter positions, it looks like it should be
// "responseObserver" but that doesn't seem similar to "context"



I'll admit my problem comes from a few directions.

1) I am not well versed in Java

2) I heavily used python's "pdb" in order to debug the classes and see what methods are available to me. I don't know of/am not proficient at a similar tool for java.

3) The documentation seems rather sparse at this point. It shows you how to set up an ssl connection on the server side, but I can't find an example of the server taking a look at request metadata, as I have shown in python.

Could someone please give me an idea of how to do this, or perhaps show me a useful debugging tool for java in the same vein of python's pdb?


I needed to first write a definition implementing the interface ServerInterceptor.

private class TestInterceptor implements ServerInterceptor {

Then, before actually binding my service and building my server, I needed to do this.

TestImpl service = new TestImpl();
ServerServiceDefinition intercepted = ServerInterceptors.intercept(service, new TestInterceptor());

Now I was able to create the server.

server = NettyServerBuilder.forPort(port)

// enable tls
new File(serverCert),
new File(serverKey)
intercepted // had been "new TestImpl()"


This allowed my ServerInterceptor to actually be called when I fired off a client side request.

This link was quite helpful in figuring this out.

Answer Source

Use a ServerInterceptor and then propagate the identity via Context. This allows you to have a central policy for authentication.

The interceptor can retrieve the identity from Metadata headers. It should then validate the identity. The validated identity can then be communicated to the application (i.e., testHello) via io.grpc.Context:

static final Context.Key<Object> USER_IDENTITY
    = Context.key("identity"); // "identity" is just for debugging

<ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(
    ServerCall<ReqT, RespT> call,
    Metadata headers,
    ServerCallHandler<ReqT, RespT> next) {
  // You need to implement validateIdentity
  Object identity = validateIdentity(headers);
  if (identity == null) { // this is optional, depending on your needs
    // Assume user not authenticated
    call.close(Status.UNAUTENTICATED.withDescription("some more info"),
               new Metadata());
    return new ServerCall.Listener() {};
  Context context = Context.current().withValue(USER_IDENTITY, identity);
  return Contexts.interceptCall(context, call, headers, next);

public void testHello(TestRequest req, StreamObserver<TestResponse> responseObserver) {
  Object identity = USER_IDENTITY.get();
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download