Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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:

  1. Looks for the x-user-authorization header (a raw JWT access token).
  2. Loads the current AuthConfig from Redis via find_config_from_redis so it can decode the token with the same secret and issuer values used during minting.
  3. Decodes and validates the JWT using the access-token audience/issuer rules, producing a UserId newtype when everything checks out.
  4. Stores that UserId in 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:

  1. Register it after the .layer(self.user_auth_middleware) call in GrpcWorker::server_ready.
  2. In every handler, call UserId::from_request before executing business logic.
  3. Treat the returned Uuid as 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】