interceptor

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 7, 2026 License: MIT Imports: 24 Imported by: 0

Documentation

Overview

Package interceptor provides the gRPC unary server interceptor chain that aligns the gRPC transport with the existing HTTP middleware stack (runtime/http/middleware): RequestID, Tracing, Metrics, Auth, and Recovery.

The interceptors are composed by NewUnaryChain into a single grpc.ServerOption. bootstrap (a later PR) installs that option on the adapters/grpc server; this package owns no server lifecycle.

Chain order

NewUnaryChain composes the interceptors in this fixed order (outermost → innermost), where the first argument to grpc.ChainUnaryInterceptor is the outermost wrapper closest to the transport:

RequestID → Tracing → Metrics → Auth → Recovery → handler

Recovery is INNERMOST, not outermost. This deliberately diverges from the HTTP middleware order (where Recovery sits inside Tracing/Metrics but its placement is driven by the HTTP ResponseWriter commit-ordering constraint — Recovery must own the writer to emit a 500 body). gRPC has no such constraint: a status code is a return value, so a panic recovered by the innermost interceptor and converted to codes.Internal propagates outward as a normal (resp, err) return that the outer Metrics and Tracing interceptors observe accurately. Placing Recovery innermost is the grpc-ecosystem go-grpc-middleware consensus, which documents recovery-last so metrics and logging see the converted status.

ref: grpc-ecosystem/go-grpc-middleware interceptors/recovery/interceptors.go ref: go-kratos/kratos transport/grpc/interceptor.go

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func NewUnaryChain

func NewUnaryChain(deps Deps) grpc.ServerOption

NewUnaryChain composes the unary interceptors into a single grpc.ServerOption. This is the single authoritative composition point; the order is fixed here (RequestID outermost, Recovery innermost) and guarded by archtest GRPC-INTERCEPTOR-CHAIN-ORDER-01. See the package doc for the order rationale.

func UnaryAuth

func UnaryAuth(verifier auth.IntentTokenVerifier, opts ...AuthOption) grpc.UnaryServerInterceptor

UnaryAuth returns an interceptor that extracts a bearer token from the incoming metadata, verifies it via runtime/auth.AuthenticateBearer (the shared transport-agnostic core), applies the password-reset gate, and on success forwards the principal-enriched context to the handler. Failures map directly to gRPC status codes (Unauthenticated / Unavailable / PermissionDenied), mirroring the HTTP handleAuthRequest classification.

The verifier is required: a nil verifier is a wiring bug that fails fast at construction (programmer-error panic). For a security interceptor this is correct — the server must refuse to start rather than boot and reject every request, which would be indistinguishable from an outage.

func UnaryMetrics

func UnaryMetrics(collector metrics.GRPCCollector, clk clock.Clock) grpc.UnaryServerInterceptor

UnaryMetrics returns an interceptor that records grpc_server_requests_total and grpc_server_request_duration_seconds via the given collector. The metric labels are: method (info.FullMethod), code (the gRPC status code name derived from the handler's returned error), and cell. The cell label is resolved through the sealed metrics.ResolveCellLabel funnel — passed a nil closed set because gRPC cell attribution is not yet wired (#1383), so the funnel always degrades to metrics.RuntimeCellSentinel ("_runtime") for now. When attribution lands, the nil is replaced by the assembly closed set and the cell label reflects the owning cell with no other change. This mirrors runtime/http/middleware.Metrics.

collector and clk are required: a nil collector or clock is a wiring bug that fails fast at construction (programmer-error panic, like MustHaveClock) rather than nil-dereferencing on the first RPC where UnaryRecovery would mask it as a generic codes.Internal.

func UnaryRecovery

func UnaryRecovery() grpc.UnaryServerInterceptor

UnaryRecovery returns the innermost interceptor: it recovers panics raised by the handler, logs the redacted panic value plus stack via slog.Error, and converts the panic into a codes.Internal status returned to the client. It does NOT re-panic — the panic is collapsed into a return value so the outer Metrics and Tracing interceptors observe a clean codes.Internal. This mirrors runtime/http/middleware.Recovery (and the go-grpc-middleware / Kratos recovery convention); because it never calls panic() itself it is outside the PANIC-REGISTERED-01 funnel.

func UnaryRequestID

func UnaryRequestID() grpc.UnaryServerInterceptor

UnaryRequestID returns the outermost interceptor: it derives a request id (reused from incoming metadata when valid, otherwise freshly generated) and stores it under both ctxkeys.RequestID and ctxkeys.CorrelationID so that the downstream Tracing / Metrics / Recovery interceptors and any errcode emitted by the handler carry a stable correlation id. It mirrors runtime/http/middleware.RequestID; the ctxkeys helpers are shared and carry no funnel restriction.

func UnaryTracing

func UnaryTracing(tracer wrapper.Tracer) grpc.UnaryServerInterceptor

UnaryTracing returns an interceptor that starts a wrapper.Span per RPC named by the full method (leading slash stripped), records rpc.* attributes, and on error records the error and sets the span status. Error redaction is owned by the otelSpan sink (SPAN-RECORD-ERROR-SEAL-01) — call sites pass the raw error. Span attributes go through wrapper.Attr (not raw attribute.String), so the adapters/otel safeStringAttr redaction funnel applies automatically — this interceptor does not touch the SPAN-SETATTR-REDACT-01 callsite set. It mirrors runtime/http/middleware.Tracing. A nil tracer degrades to NoopTracer.

Types

type AuthOption

type AuthOption func(*authConfig)

AuthOption configures the auth interceptor.

func WithPasswordResetExempt

func WithPasswordResetExempt(pred func(fullMethod string) bool) AuthOption

WithPasswordResetExempt installs a predicate marking RPC methods exempt from the password-reset gate (the gRPC analog of the HTTP route-based exempt matcher). The default (nil predicate) is fail-closed — a reset-required token is rejected on every method. Passing a nil predicate is a no-op; any previously installed predicate is retained.

func WithPublicMethod

func WithPublicMethod(pred func(fullMethod string) bool) AuthOption

WithPublicMethod installs a predicate marking RPC methods that bypass authentication (e.g. health checks). The wiring of concrete public-method sets is a later-PR concern (tracked in backlog); the default (nil predicate) is fail-closed — every method requires authentication. Passing a nil predicate is a no-op; any previously installed predicate is retained.

type Deps

type Deps struct {
	// Tracer records one span per RPC. A nil Tracer degrades to NoopTracer.
	Tracer wrapper.Tracer
	// Collector records grpc_server_* metrics.
	Collector metrics.GRPCCollector
	// Clock times request duration for the metrics interceptor (required).
	Clock clock.Clock
	// Verifier authenticates bearer tokens (required; nil fails closed).
	Verifier auth.IntentTokenVerifier
	// AuthOptions configures the auth interceptor (public-method and
	// password-reset-exempt predicates).
	AuthOptions []AuthOption
}

Deps holds the dependencies the unary interceptor chain needs. They are supplied by the composition root (bootstrap, a later PR); this package only composes them.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL