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 & Audit

The Manage service authenticates every administrative RPC call and records the privileged work that survives RBAC checks. This document captures the moving pieces so existing contributors remember how the plumbing fits together and new contributors can reuse it correctly.

Access token issuance

AdminAuthService is responsible for exchanging an API key for a signed access JWT. The AdminLogin processor performs the following steps:

  1. Look up the submitted API key with FindAdminPasskeyByToken. Unknown keys immediately return AdminLoginResult::KeyNotFound.
  2. Resolve the owning administrator via FindAdminById. Keys referencing a removed account are treated as unknown.
  3. Pull AdminJwtConfig from Redis using find_config_from_redis. The config bundle provides the HMAC/EdDSA encoder plus default issuer, audience, and expiry settings.
  4. Build AdminJwtClaims from the admin profile (ID, display name, role) and the timestamps computed from OffsetDateTime::now_utc().
  5. Sign the JWT with the encoder returned by the config and wrap the token in AdminAccessToken for the RPC response.

Every Manage client must attach the returned JWT to subsequent requests using x-admin-authorization. No refresh token logic exists—clients repeat the login flow when the token expires.

Authentication middleware

The RPC server mounts AdminAuthLayer (see rpc::middleware) on every handler that requires an authenticated admin. The middleware:

  1. Loads AdminJwtConfig from Redis (identical to the login flow) so it can reuse the configured decoder.
  2. Extracts x-admin-authorization from the incoming headers and validates the JWT. Invalid or missing tokens result in Status::unauthenticated once the gRPC method executes.
  3. Stores the authenticated administrator ID in the request extensions as AdminId so downstream handlers can fetch it with AdminId::from_request(&Request).

When you add a new RPC surface, ensure the router is wrapped with AdminAuthLayer::new(redis.clone()) and read the admin identifier from the extensions instead of parsing the header manually. This keeps every handler in sync with the central decoding logic and JWT configuration source.

Auditing and RBAC enforcement

AuditLayer wires authentication into authorization and durable audit trails. Operations that mutate state are modelled as RecordedAdminOperation<T> where T: AdminOperation describes the action being performed. Wrapping a processor with the layer performs the following steps:

  1. Reload the administrator from the database (FindAdminById). Requests referencing a deleted admin fail with Error::PermissionsDenied.
  2. Emit tracing fields (admin_name, admin_role) for observability.
  3. Check whether the admin role satisfies the static allow-list declared on the operation type via AdminOperation::check_permission. Permission failures short-circuit the call with Error::PermissionsDenied.
  4. If permitted, transform the operation into an audit payload with to_audit_log() and persist it using AddAuditLog.
  5. Execute the wrapped processor and log success or failure.

Use AuditLayer::wrap_without_record when you only need the permission check (for example, read-only operations). Otherwise prefer wrap so the audit table stays authoritative.

Checklist for new handlers

  • Accept the admin context by calling AdminId::from_request in the RPC entry point.
  • Build the corresponding operation type that implements AdminOperation.
  • Wrap the service processor with AuditLayer::wrap (or wrap_without_record for read endpoints).
  • Propagate Error::PermissionsDenied back to the client untouched so callers see a clear 403-style error.

Following these conventions ensures every manage RPC reuses the same JWT validation, role checks, and audit recording logic.