Authentication for Other Modules
This guide explains how gRPC services outside of the auth module reuse the authentication middleware so they can trust the UserId that reaches their handlers. It focuses on the shared layer, required request metadata, and the pattern every user-facing RPC follows when extracting identity.
Middleware overview
The UserAuthLayer type wraps gRPC routers with a Tower middleware that runs before your service logic. When the layer sees an incoming request it:
- Looks for the
x-user-authorizationheader (a raw JWT access token). - Loads the current
AuthConfigfrom Redis viafind_config_from_redisso it can decode the token with the same secret and issuer values used during minting. - Decodes and validates the JWT using the access-token audience/issuer rules, producing a
UserIdnewtype when everything checks out. - Stores that
UserIdin the request extensions so downstream handlers can pull it without re-validating the token.【F:modules/auth/src/rpc/middleware.rs†L12-L110】
GrpcWorker::server_ready installs this layer globally before registering user-scoped services. Any service added after .layer(self.user_auth_middleware) automatically receives authenticated requests and does not need to declare the middleware explicitly.【F:server/src/worker/grpc.rs†L302-L349】
Required request metadata
Clients must send the access token in the x-user-authorization header on every RPC guarded by the middleware. Tokens are the opaque strings returned from login/registration flows; do not prefix them with Bearer. If the header is missing or the token fails validation, user_auth returns a Status::unauthenticated error. The layer logs the failure and forwards the request; when your handler subsequently calls UserId::from_request it will see the error and propagate the unauthenticated status back to the caller.【F:modules/auth/src/rpc/middleware.rs†L74-L110】
The middleware never accepts refresh tokens—those belong in the x-refresh-token header and are handled exclusively by the session RPC (RefreshSession).【F:modules/auth/src/rpc/middleware.rs†L82-L92】【F:modules/auth/src/rpc/auth_service.rs†L288-L331】 Keep access and refresh tokens in their respective lanes to avoid confusing downstream services.
Reading the authenticated user
Inside a gRPC handler, retrieve the caller identity by importing UserId from auth::rpc::middleware and calling UserId::from_request(&request) at the top of the method. That helper pulls the UserId extension set by the middleware and converts it back into a plain Uuid. Every user-facing module (market, telecom, shop, notification, support, etc.) follows this pattern so new services should mirror it.【F:modules/auth/src/rpc/middleware.rs†L94-L110】【F:modules/market/src/rpc/market.rs†L70-L132】【F:modules/telecom/src/rpc/telecom.rs†L69-L265】【F:modules/shop/src/rpc/order.rs†L149-L321】
Avoid re-parsing JWTs or threading user IDs through request payloads; the middleware ensures a single source of truth. If UserId::from_request returns Status::unauthenticated, simply propagate that error to the caller so clients know to refresh their session.
Adding a new authenticated service
When you introduce a new gRPC server that should require user authentication:
- Register it after the
.layer(self.user_auth_middleware)call inGrpcWorker::server_ready. - In every handler, call
UserId::from_requestbefore executing business logic. - Treat the returned
Uuidas the authenticated principal and authorize against your domain resources accordingly.
If you need unauthenticated entry points (e.g., public lookups), mount that service before the middleware layer or expose the RPC through the UserAuth service instead. Mixing authenticated and unauthenticated handlers in the same service leads to confusing guarantees, so prefer splitting them.
Testing tips
Integration tests that hit authenticated RPCs should obtain a valid access token through the login helpers and attach it to the request metadata under x-user-authorization. When writing unit tests that call handlers directly, construct a tonic::Request and insert a UserId into its extensions to simulate the middleware path. This mirrors what production infrastructure does and keeps your tests aligned with the runtime behavior.【F:modules/auth/src/rpc/middleware.rs†L30-L110】