Skip to content

fix: demote non-gRPC auth error log from Error to Debug - #18

Merged
maoueh merged 1 commit into
developfrom
feature/demote-non-grpc-auth-error-log
Jul 31, 2026
Merged

fix: demote non-gRPC auth error log from Error to Debug#18
maoueh merged 1 commit into
developfrom
feature/demote-non-grpc-auth-error-log

Conversation

@maoueh

@maoueh maoueh commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Problem

Both auth middlewares log every non-gRPC error returned by the dauth.Authenticator at Error level.

status.FromError returns ok=false for any error that is not a google.golang.org/grpc/status error and does not implement GRPCStatus(). Authenticator implementations that return a plain application error on rejection — no token, malformed Authorization header, expired/invalid JWT, unknown API key — therefore land in the else branch and get logged at Error.

That is by far the most common outcome for anonymous traffic and for a browser tab that has not logged in yet. Real-world result in sf-saas-priv's portal-api, on a single page load:

[2026-07-31 13:42:35.335 EDT] ERROR (sfsaas.portal-api) authentication service via Connect-Web middleware non-gRPC error {"error":"unauthenticated"}
... x8 ...

A client failing to authenticate is a client-side condition, not a server fault. At Error level it buries genuine errors and lights up error-rate alerting.

Change

Demote that branch to Debug in both middleware/connect and middleware/grpc. Same message text, same zap.Error(err) field.

Genuine auth-service failures — codes.Internal, codes.Unavailable, codes.Unknown — are untouched and still log at Error.

Note on the Connect middleware

middleware/connect already had a partial gate from 1ec7a43: logger.Check(level, ...), where level is Debug only when ctx.Err() != nil || dauth.IsErrInvalidAuthentication(err). Authenticators returning a plain error rather than a *dauth.ErrInvalidAuthentication still evaluated to Error, so the flood was real. The else branch is now unconditionally Debug; the level variable continues to govern the Internal/Unavailable/Unknown branch.

Compatibility

No behavior change beyond log level — obfuscateErrorMessage returns exactly the errors it returned before in every branch. Consumers that map the returned error to their own status code (e.g. sf-saas-priv's outer ErrorMappingInterceptor, which maps the plain error to connect.CodeUnauthenticated with error details attached) are unaffected.

Verification

go build ./..., go vet ./middleware/... and go test ./... all clean.

A client failing to authenticate is a client-side condition, not a
server fault. Both the Connect and gRPC auth middlewares logged every
non-gRPC error from the authenticator at Error level, which floods logs
and lights up error-rate alerting on ordinary anonymous traffic (no
token, malformed Authorization header, expired JWT, unknown API key).

Demote that branch to Debug in middleware/connect and middleware/grpc.
Genuine auth-service failures (Internal, Unavailable, Unknown) still log
at Error. Returned errors are unchanged, so consumers mapping the
returned error to their own status code are unaffected.
@maoueh
maoueh merged commit 2249b2a into develop Jul 31, 2026
2 checks passed
@maoueh
maoueh deleted the feature/demote-non-grpc-auth-error-log branch July 31, 2026 18:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant