Lesson 11 · Interceptors, middleware & auth
Interceptors: unary & stream
gRPC's middleware — the code that wraps every RPC.
Your win: explain what a gRPC interceptor is, read the unary and
stream signatures, and recognise the enrich-ctx-then-call-handler
pattern that runs on every request in your services.
An interceptor wraps every RPC
An interceptor runs code before and after a handler, for every call — it's gRPC's equivalent of HTTP middleware.1 It's where cross-cutting concerns live — auth, logging, tracing, metrics, panic-recovery — so your handlers stay pure business logic.
The unary server signature
func(ctx context.Context, req interface{},
info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error)
You get the ctx and req, plus info (which method
is being called) and handler (the next thing in line — the real handler, or
the next interceptor). The pattern: do work, optionally enrich ctx, then
return handler(ctx, req) — and you can inspect the result
after.
func (a *Auth) UnaryServerInterceptor(ctx, req, info, handler) (interface{}, error) {
// …verify JWT from metadata (Lesson 10)…
ctx = glInterceptors.ContextWithJWTClaims(ctx, claims) // enrich ctx
return handler(ctx, req) // call down the chain
}
The stream server signature
func(srv interface{}, ss grpc.ServerStream,
info *grpc.StreamServerInfo, handler grpc.StreamHandler) error
Same idea, but it wraps the stream (ss) instead of a
request/response — used by the recovery and logging interceptors on tom's streaming RPCs.
handler(ctx, req). Because it's an interceptor, every RPC in the
service is authenticated without a single line in any handler. That's the payoff — and
it's why the handlers you write are pure business logic.
handler is just the next
func; you choose whether/when to call it, and what to do with its result.
gRPC — Interceptors guide + grpc-go interceptor example
The official concept (server vs client, unary vs stream) and a runnable Go example of each signature.
→ grpc.io/docs/guides/interceptors
→ grpc-go — interceptor example
Check yourself (from memory)
Q1. A gRPC interceptor is best described as…
Q2. A unary server interceptor ends by…
handler) —
after enriching ctx — and can inspect the result afterward.
Q3. gRPC interceptors come in which two kinds?
func(ctx, req, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler)
(resp, err). Core pattern: do work / enrich ctx, then
return handler(ctx, req) — with optional before-and-after logic. Keeps
handlers pure business logic.