Documentation Index
Fetch the complete documentation index at: https://mintlify.com/CodexaCP/DG_APK/llms.txt
Use this file to discover all available pages before exploring further.
SessionService is the single authoritative source of authentication state for Dragon Guard Handheld. It owns all reading, writing, and clearing of session data; no other part of the application touches the token or company context directly. Every protected HTTP request is decorated by AuthenticatedHttpMessageHandler, which reads from SessionService at call-time — there is no separate in-memory cache to synchronise. This design means that a sign-out or a token invalidation is immediately effective for all subsequent requests, regardless of which screen the operator is on.
Session storage keys
SessionService defines a fixed set of string constants for the underlying storage keys. These names are the canonical identifiers used in SecureStorage and in the Preferences fallback.
Session data is written to
SecureStorage first. On devices where SecureStorage is unavailable (older Android versions without a compatible hardware-backed keystore, or certain emulators), the service automatically falls back to Preferences. Preferences data is not encrypted at the OS level, so production deployments should always use hardware that supports Android Keystore.Stored fields
| Field | Storage key | Type | Description |
|---|---|---|---|
| Bearer token | auth_token | string | JWT issued by the server on successful login |
auth_email | string | Operator’s email address | |
| Full name | auth_full_name | string | Operator’s display name |
| Companies | auth_companies | JSON string | Serialised List<AuthCompanyAccessDto> |
| Active company ID | auth_active_company_id | string (GUID) | The single operational company GUID for this session |
State properties
Three computed properties expose the session validity to the rest of the application without requiring callers to inspect raw storage values.| Property | Returns true when |
|---|---|
IsAuthenticated | Token is a non-empty string |
HasAmbiguousCompanyContext | The session contains more than one company entry |
HasValidOperationalContext | Token is present, an active company is set, and there is no ambiguity |
InitializeAsync — boot-time session restore
Called once during app startup,InitializeAsync reads every storage key and reconstructs the in-memory session state. If the token is missing, the company list is empty, or the session contains more than one company, all fields are cleared from both SecureStorage and Preferences to prevent a stale ambiguous session from surviving a restart.
InitializeAsync completes, IsAuthenticated and HasValidOperationalContext reflect the actual state and the app router can decide whether to show the login screen or navigate directly to the home screen.
SignInAsync — writing a new session
SessionService.SignInAsync accepts the AuthSessionResponseDto returned by AuthService and enforces the single-company rule before writing anything to storage. It filters out entries where CompanyId is Guid.Empty, then checks the count.
WriteAsync calls have been reached, so no partial session is persisted.
SignOutAsync — full session teardown
SignOutAsync zeroes every in-memory field and removes all five storage keys. It fires SessionChanged after clearing so that any UI components observing the event can react immediately.
SignOutAsync removes keys from both SecureStorage and Preferences via the shared Remove helper, ensuring no token fragment survives in either storage layer after sign-out regardless of which layer was used during sign-in.AuthenticatedHttpMessageHandler — automatic header injection
AuthenticatedHttpMessageHandler is a DelegatingHandler registered in the DI container. Every HTTP client that needs authentication routes its requests through this handler without any call-site changes.
What the handler does
Guard: check IsAuthenticated
Before forwarding the request, the handler checks
SessionService.IsAuthenticated. If the token is missing, it calls SignOutAsync and navigates to the login page, then throws to abort the original request.Inject Authorization header
The handler sets the
Authorization header to Bearer <token> from the current in-memory token value.Inject X-Company-Id header
If an active company GUID is set and the request does not already carry the header (to allow callers to override), the handler appends it.The
X-Company-Id value is always the active company’s GUID from SessionService. It is never hardcoded and never derived from a local cache — any call to SetActiveCompanyAsync or SignOutAsync immediately affects the next outgoing request.Request headers produced
Every protected API call carries these two headers:X-Company-Id to scope all data access, audit logging, and permission checks to the operator’s single operational tenant. Requests that omit this header or carry an incorrect GUID will be rejected by the backend, which is an additional safeguard on top of the JWT-level tenant claim.
Protected navigation
NavigationService checks SessionService.IsAuthenticated before pushing any protected page onto the navigation stack. If the token is absent at navigation-time — for example, because SignOutAsync was called mid-session by the HTTP handler — the push is blocked and the app redirects to login instead.
After a sign-out triggered by a 401/403 API response, AuthenticatedHttpMessageHandler calls app.ShowLoginAsync on the main thread. This replaces the navigation root with the login page, which means Android’s hardware back button cannot navigate back into protected screens — the back stack no longer contains them.
SessionChanged event
Every mutating operation (InitializeAsync, SignInAsync, SignOutAsync, SetActiveCompanyAsync) fires the SessionChanged event after completing. ViewModels and services that need to react to auth state changes subscribe to this event rather than polling properties.