Every production gRPC service needs encryption and caller identity.
Metadata is gRPC's name for headers: key-value pairs sent at the start of a call (and trailers at the end). Keys are lowercase ASCII; keys ending in -bin carry binary values. Use metadata for cross-cutting data: auth tokens, request IDs, tracing context, never for business fields that belong in the message.
In grpc-js: const md = new grpc.Metadata(); md.set("x-request-id", id); then pass it as the second argument to a call. Servers read call.metadata.get("authorization"), and can send headers with call.sendMetadata() and trailers in the callback.
Transport security: use grpc.credentials.createSsl(rootCerts, key, cert) on clients and grpc.ServerCredentials.createSsl(...) on servers. Supplying client key and certificate gives mutual TLS (mTLS), common inside service meshes, where the peer certificate identifies the calling service.
Per-call credentials for end-user tokens: build call credentials with grpc.credentials.createFromMetadataGenerator() and combine them with channel credentials via combineChannelCredentials(). gRPC refuses to send call credentials over an insecure channel, which protects tokens from leaking in plaintext.
On the server, validate the token in an interceptor or a shared helper, reject with UNAUTHENTICATED, and put the identity somewhere handlers can read it.
Example
import * as grpc from "@grpc/grpc-js";
import * as protoLoader from "@grpc/proto-loader";
const { hello } = grpc.loadPackageDefinition(protoLoader.loadSync("hello.proto"));
const server = new grpc.Server();
server.addService(hello.v1.Greeter.service, {
SayHello: (call, callback) => {
const [auth] = call.metadata.get("authorization");
if (auth !== "Bearer s3cret") {
return callback({ code: grpc.status.UNAUTHENTICATED, details: "bad token" });
}
callback(null, { message: `Hello, ${call.request.name}` });
},
});
server.bindAsync("127.0.0.1:50055", grpc.ServerCredentials.createInsecure(), () => {
const client = new hello.v1.Greeter("127.0.0.1:50055", grpc.credentials.createInsecure());
const md = new grpc.Metadata();
md.set("authorization", "Bearer s3cret");
client.SayHello({ name: "Ann" }, md, (err, reply) => {
console.log(reply.message); // Hello, Ann
server.forceShutdown();
});
});Remember
- Metadata = headers/trailers; keys lowercase,
-binfor binary - TLS via createSsl; client certs give mutual TLS
- Call credentials attach per-call tokens and require a secure channel
Watch out for
- Putting user IDs or other business data in metadata instead of the request message.