No. A unary server interceptor runs for unary calls, one request and one response. Streaming methods need a separate stream interceptor, or they run without the check. OWASP's gRPC cheat sheet warns that registering a unary interceptor does not protect streaming methods. Register both, then test every call type.
The four call types
gRPC has four kinds of method: unary, server streaming, client streaming and bidirectional streaming. Interceptors are hooks that wrap calls. In Go, for example, unary and stream interceptors are separate types with different signatures. Other languages have equivalents with similar splits.
A team writes an authentication interceptor, tests it on a login protected unary method, sees a denial for missing tokens, and moves on. If a streaming method such as a log tail or a chat feed was added later, the interceptor never ran for it.
What OWASP says
The cheat sheet's token example is explicitly a unary server interceptor. It states that protected streaming RPCs need equivalent checks in a stream server interceptor before invoking the stream handler. It makes the same point about rate limiting: the example limits unary RPCs only, and stream admission limits need a stream interceptor, with per message limits enforced inside the stream, because limiting stream creation alone does not limit the messages sent over an existing stream.
How to audit your service
- List every method in your
.protofiles and mark its call type. - For each streaming method, check the server construction code for a stream interceptor that performs authentication.
- Call each streaming method with no credentials and with an invalid token, using a test client. Confirm both are refused with an unauthenticated status.
- Call each with a valid token that lacks permission. Confirm a permission denied status.
- Repeat for authorization. Method level checks should live in a shared function so unary and stream paths use the same rules.
- Add these tests to CI so a new streaming method cannot ship without them.
OWASP recommends status codes to match: UNAUTHENTICATED for authentication failures, PERMISSION_DENIED for authorization failures and INVALID_ARGUMENT for validation errors.
A stream is long lived
A stream may stay open for a long time. A token valid at connection time may expire or be revoked while the stream runs. Decide how your service handles that: check expiry periodically inside the stream, cap session duration, or require reconnection. OWASP's cheat sheet recommends monitoring maximum messages per stream and maximum session duration.
The same gap appears in other long lived channels. A websocket authorised once can live for hours, and the lesson carries over.
Common gaps
| Gap | Symptom | Fix |
|---|---|---|
| Only a unary interceptor | Streaming methods accept anonymous calls | Add stream interceptor |
| Separate auth logic per type | Rules drift apart | Share one authorization function |
| No expiry check mid stream | Revoked tokens keep streaming | Re check or cap duration |
| Rate limit on stream creation only | One stream floods messages | Limit messages per stream |
Try it yourself
Click through it at your own pace, or open it full screen.
Look at how a code scan points to the exact lines, then think about where your interceptors are registered.
Quick check
Do I need two interceptors for authentication?
In languages that split them, yes: one for unary calls and one for streams. Both should call the same shared authentication and authorization logic.
How do I test that streams are protected?
Call each streaming method without a token, with a bad token and with a low privilege token, and confirm each is refused with the right status.
Safeguard scans your dependencies and SBOMs for known vulnerabilities, including gRPC libraries, and applies reachability analysis to show which matter. A free scan is at gold.safeguard.sh/scan.
Sources
Last reviewed: 19 October 2026.