gRPC Authentication Middleware#
Flipt's gRPC authentication middleware lives in internal/server/authn/middleware/grpc/middleware.go and enforces identity checks on all incoming gRPC unary calls. It is composed of several interceptors that run in sequence, each responsible for a different authentication mechanism or enforcement check.
Interceptor Chain#
The interceptors are assembled in internal/cmd/grpc.go and appended to the base interceptor list. The core auth interceptors are constructed by authenticationGRPC() and then followed by FliptAcceptServerVersionUnaryInterceptor and EvaluationUnaryInterceptor.
The four primary authentication interceptors are:
| Interceptor | Purpose |
|---|---|
ClientTokenAuthenticationInterceptor | Validates Bearer <token> from authorization header or cookie |
JWTAuthenticationInterceptor | Validates JWT <token> from authorization header |
AuthenticationRequiredInterceptor | Enforces that an Authentication object is present on the context |
EmailMatchingInterceptor | Restricts OIDC-authenticated requests to an allowlist of email regexes |
A fifth interceptor, NamespaceMatchingInterceptor, enforces namespace scoping for static token authentications.
Token extraction reads from the gRPC metadata authorization key (expecting Bearer <token> or JWT <token>) or falls back to the grpcgateway-cookie header .
Skipping Authentication#
Servers can opt out of authentication in two ways:
- Interface-based skip: implement
SkipsAuthenticationServer(SkipsAuthentication(ctx) bool) . - Instance-based skip: pass
WithServerSkipsAuthentication(server)when wiring up interceptors .
In practice, the health server always skips authentication , and the management, evaluation, OFREP servers can be selectively excluded via config flags authentication.exclude.* .
Log Levels for Unauthenticated Requests#
All auth failures emit logs at ERROR level. This is consistent across all interceptors:
AuthenticationRequiredInterceptor: logs"unauthenticated"with reason"authentication required".ClientTokenAuthenticationInterceptor: logs"unauthenticated"for missing metadata, missing token, token lookup failure, and expired tokens .JWTAuthenticationInterceptor: logs"unauthenticated"for missing metadata, missing token, and validation errors .EmailMatchingInterceptor: logs"unauthenticated"with reason"email is not allowed"atERROR.- Skipped servers log
"skipping authentication for server"atDEBUGlevel .
Log Level Configuration#
Flipt exposes two separate log level knobs :
| Config key | YAML key | Default | Purpose |
|---|---|---|---|
log.level | level | INFO | Global application log level |
log.grpc_level | grpc_level | ERROR | Minimum level for internal gRPC library messages |
The grpc_level is applied to the underlying gRPC framework logger (not to Flipt's own auth middleware) via grpc_zap.ReplaceGrpcLoggerV2 . This means:
- Auth middleware failures are controlled by the global
log.level. They are always emitted atERROR, so they appear at any level setting ofERRORor below (i.e.,DEBUG,INFO,WARN,ERROR). - Internal gRPC library noise (e.g., transport-layer events) is controlled by
log.grpc_level, which defaults toERRORto suppress verbose gRPC framework messages.
Environment variable overrides follow the pattern FLIPT_LOG_LEVEL and FLIPT_LOG_GRPC_LEVEL .
The LogConfig struct defaults are set in :
log:
level: INFO
grpc_level: ERROR
encoding: console
Key Source Files#
| File | Purpose |
|---|---|
internal/server/authn/middleware/grpc/middleware.go | All gRPC auth interceptor implementations |
internal/config/log.go | LogConfig struct and defaults |
internal/cmd/grpc.go | Interceptor assembly, gRPC log level wiring |
| Configuration overview | Reference table for log.level and log.grpc_level |