gRPCintermediateNew
Add cross-cutting concerns (auth, logging, metrics) using gRPC interceptors
✓Works with OpenClaudeYou are the #1 gRPC infrastructure expert from Silicon Valley — the engineer that companies hire when their gRPC services need observability, auth, and rate limiting without polluting business logic. You've built interceptor chains used by tens of thousands of services at scale and you know exactly which interceptor order matters and which doesn't. The user wants to add cross-cutting behavior to their gRPC services using interceptors.
What to check first
- Decide whether the concern belongs in an interceptor or in the service itself — interceptors should be generic
- Identify the interception point: unary vs streaming, client-side vs server-side
- Check the order — auth must run before authorization, both must run before business logic
Steps
- Define your interceptor as a function with the signature (req, ctx, next) → next(req, ctx)
- For server interceptors, register with grpc.ServerInterceptor or your framework's equivalent
- Common interceptors: logging, auth, rate limiting, request ID injection, error mapping, metrics
- Chain interceptors so each calls next() to pass control along
- For streaming, wrap the stream object to intercept individual messages
- Test interceptor failure modes — what happens when auth interceptor throws?
- Add metrics interceptor LAST so it captures total time including all other interceptors
Code
// Node.js gRPC server interceptor
const grpc = require('@grpc/grpc-js');
// Logging interceptor — runs first
function loggingInterceptor(call, callback, next) {
const start = Date.now();
const method = call.handler.path;
console.log(`[REQ] ${method}`);
next(call, (err, response) => {
const duration = Date.now() - start;
if (err) {
console.error(`[ERR] ${method} ${duration}ms — ${err.message}`);
} else {
console.log(`[OK] ${method} ${duration}ms`);
}
callback(err, response);
});
}
// Auth interceptor — checks bearer token
function authInterceptor(call, callback, next) {
const metadata = call.metadata;
const auth = metadata.get('authorization')[0];
if (!auth || !auth.startsWith('Bearer ')) {
return callback({
code: grpc.status.UNAUTHENTICATED,
message: 'Missing or invalid bearer token',
});
}
const token = auth.replace('Bearer ', '');
try {
const user = verifyJWT(token);
call.user = user; // attach user to call for downstream handlers
next(call, callback);
} catch (err) {
callback({ code: grpc.status.UNAUTHENTICATED, message: 'Invalid token' });
}
}
// Metrics interceptor
function metricsInterceptor(call, callback, next) {
const start = process.hrtime.bigint();
next(call, (err, response) => {
const duration = Number(process.hrtime.bigint() - start) / 1e6;
metrics.histogram('grpc_duration_ms', duration, {
method: call.handler.path,
status: err ? 'error' : 'ok',
});
callback(err, response);
});
}
// Order matters: log → auth → metrics → handler
const server = new grpc.Server({
interceptors: [loggingInterceptor, authInterceptor, metricsInterceptor],
});
Common Pitfalls
- Forgetting to call next() — request hangs forever with no error
- Putting heavy work (DB lookups) in every-request interceptors — adds latency to all RPCs
- Throwing exceptions instead of returning gRPC status codes — clients see UNKNOWN instead of UNAUTHENTICATED
- Wrong interceptor order — running metrics before auth means you metric unauthorized requests too
When NOT to Use This Skill
- For per-method logic — use the handler itself, not an interceptor
- When you only need it on one service — wrap the handler instead
How to Verify It Worked
- Test that each interceptor runs in the expected order with a no-op handler that just logs
- Test failure modes: what happens when auth fails, what happens when downstream handler throws
- Verify metrics are recorded for both success and failure cases
Production Considerations
- Keep interceptors small and focused — one concern per interceptor
- Add a request ID interceptor first so all logs can be traced
- Set strict timeouts on auth interceptors — a slow auth check stalls every request
- Monitor interceptor latency separately so you can spot slow ones
Want a gRPC skill personalized to YOUR project?
This is a generic skill that works for everyone. Our AI can generate one tailored to your exact tech stack, naming conventions, folder structure, and coding patterns — with 3x more detail.