mas_axum_utils/log_context.rs
1// Copyright 2026 Element Creations Ltd.
2//
3// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
4// Please see LICENSE files in the repository root for full details.
5
6//! Ergonomic glue between domain types and the [`LogContext`] requester slot.
7//!
8//! Auth-resolution sites can call `value.maybe_record_as_requester()` on a
9//! [`User`], [`BrowserSession`], [`Session`], [`CompatSession`] or [`Client`]
10//! instead of reaching for [`LogContext::maybe_set_requester`] + [`Requester`]
11//! directly. Each call site should record the entity that *authenticated the
12//! request* exactly once; [`LogContext`] is first-writer-wins, so an accidental
13//! second call is harmless.
14
15use mas_context::{LogContext, Requester};
16use mas_data_model::{BrowserSession, Client, CompatSession, Session, User};
17
18pub trait RecordAsRequester {
19 /// Record `self` as the [`Requester`] on the current [`LogContext`], if
20 /// any.
21 ///
22 /// First writer wins — calling on a request that already has a requester
23 /// recorded is a no-op.
24 fn maybe_record_as_requester(&self);
25}
26
27impl RecordAsRequester for User {
28 fn maybe_record_as_requester(&self) {
29 LogContext::maybe_set_requester(Requester::user(self.id, self.username.clone()));
30 }
31}
32
33impl RecordAsRequester for BrowserSession {
34 fn maybe_record_as_requester(&self) {
35 self.user.maybe_record_as_requester();
36 }
37}
38
39impl RecordAsRequester for Session {
40 /// Records the `OAuth2` session's user (without a username) when it has
41 /// one, otherwise the client acting on its own behalf
42 /// (client-credentials).
43 fn maybe_record_as_requester(&self) {
44 if let Some(user_id) = self.user_id {
45 LogContext::maybe_set_requester(Requester::user_id_only(user_id));
46 } else {
47 LogContext::maybe_set_requester(Requester::oauth2_client(self.client_id));
48 }
49 }
50}
51
52impl RecordAsRequester for CompatSession {
53 fn maybe_record_as_requester(&self) {
54 LogContext::maybe_set_requester(Requester::user_id_only(self.user_id));
55 }
56}
57
58impl RecordAsRequester for Client {
59 fn maybe_record_as_requester(&self) {
60 LogContext::maybe_set_requester(Requester::oauth2_client(self.id));
61 }
62}