Authentication & Session Overview
How WildwoodComponents handles authentication, JWT token lifecycle, session management, and multi-tenant identity across Blazor Server, WebAssembly, and MAUI applications.
AppId for multi-tenant isolation.
Architecture Overview
The authentication system consists of three primary layers that work together to provide a seamless login experience:
| Layer | Class | Responsibility |
|---|---|---|
| UI | AuthenticationComponent |
Blazor component rendering login/registration forms, OAuth buttons, passkey prompts, and 2FA challenge screens |
| Service | AuthenticationService |
HTTP client that calls WildwoodAPI endpoints, stores tokens via ILocalStorageService, and fires auth change events |
| Session | WildwoodSessionManager |
Manages JWT lifecycle: proactive refresh timers, reactive 401 handling, session expiry detection, and app resume recovery |
End-to-End Authentication Flow
The following describes the complete path from user action to established session:
User enters credentials
|
v
AuthenticationComponent (Blazor UI)
| Calls AuthenticationService.LoginAsync()
v
AuthenticationService (HTTP Client)
| POST /api/auth/login { Username, Password, AppId, Platform, DeviceInfo }
v
WildwoodAPI (Server)
| Validates credentials, checks 2FA, generates JWT + RefreshToken
v
AuthenticationResponse returned
| Contains: JwtToken, RefreshToken, UserId, Email, Roles, Permissions
| May contain: RequiresTwoFactor, RequiresPasswordReset
v
AuthenticationService stores tokens
| localStorage: accessToken, refreshToken, user
| Sets Authorization header on HttpClient
| Fires OnAuthenticationChanged event
v
WildwoodSessionManager.LoginAsync()
| Stores auth data + session expiry in localStorage
| Sets token on IAIService (cross-service sync)
| Schedules proactive refresh timer at 80% of JWT lifetime
v
Session established - app continues with authenticated user
Core Components
AuthenticationComponent
The primary UI component that handles all authentication modes. It inherits from BaseWildwoodComponent for automatic error handling and loading state management.
<AuthenticationComponent
AppId="@AppId"
OnAuthenticationSuccess="@HandleLogin"
OnAuthenticationError="@HandleError"
ShowPasswordField="true"
ShowDetailedErrors="false" />
| Parameter | Type | Description |
|---|---|---|
AppId |
string? |
The application ID for multi-tenant scoping. Determines which auth providers, captcha config, and password policies apply. |
OnAuthenticationSuccess |
EventCallback<AuthenticationResponse> |
Callback fired after successful authentication (including post-2FA). Receives the full AuthenticationResponse. |
OnAuthenticationError |
EventCallback<string> |
Callback fired when authentication fails. Receives the error message string. |
ShowPasswordField |
bool |
Whether to show the password input. Defaults to true. Set to false for OAuth-only flows. |
ShowDetailedErrors |
bool |
Whether to display detailed error messages. Defaults to true. Can be overridden by server-side AuthenticationConfiguration.ShowDetailedErrors. |
Title |
string? |
Custom title for the auth card. Defaults to "Sign In" or "Create Account" depending on mode. |
AvailableProviders |
List<AuthProvider>? |
Pre-loaded auth providers. If null, the component fetches them from the API using the AppId. |
CaptchaConfig |
CaptchaConfiguration? |
Pre-loaded captcha configuration. If null, fetched automatically. |
AuthConfig |
AuthenticationConfiguration? |
Pre-loaded authentication configuration. If null, fetched automatically. |
AuthenticationService
The service layer that communicates with the WildwoodAPI. It is registered as a scoped service and uses HttpClient with the configured base URL.
public interface IAuthenticationService
{
Task<AuthenticationResponse> LoginAsync(LoginRequest request);
Task<AuthenticationResponse> RegisterAsync(RegistrationRequest request);
Task<AuthenticationResponse> RegisterWithTokenAsync(RegistrationRequest request);
Task<AuthenticationResponse> AuthenticateWithProviderAsync(string providerName, string appId);
Task<List<AuthProvider>> GetAvailableProvidersAsync(string appId);
Task<CaptchaConfiguration?> GetCaptchaConfigurationAsync(string appId);
Task<AuthenticationConfiguration?> GetAuthenticationConfigurationAsync(string appId);
Task<bool> RefreshTokenAsync();
Task LogoutAsync();
// Passkey/WebAuthn
Task<object> GetPasskeyAuthenticationOptionsAsync(string appId);
Task<AuthenticationResponse> VerifyPasskeyAuthenticationAsync(string appId, JsonElement credential);
// Two-Factor
Task<TwoFactorSendCodeResponse> SendTwoFactorCodeAsync(string sessionId);
Task<TwoFactorVerifyResponse> VerifyTwoFactorCodeAsync(TwoFactorVerifyRequest request);
Task<TwoFactorVerifyResponse> VerifyTwoFactorRecoveryCodeAsync(string sessionId, string recoveryCode, string ipAddress);
event Action<AuthenticationResponse>? OnAuthenticationChanged;
event Action? OnLogout;
}
WildwoodSessionManager
Orchestrates session lifecycle. See the Session Management page for a deep dive.
public interface IWildwoodSessionManager : IDisposable
{
bool IsAuthenticated { get; }
bool IsInitialized { get; }
string? AccessToken { get; }
string? UserId { get; }
string? UserEmail { get; }
AuthenticationResponse? CurrentUser { get; }
Task InitializeAsync();
Task<bool> LoginAsync(AuthenticationResponse authResponse);
Task LogoutAsync();
Task<bool> RefreshTokenAsync();
Task OnAppResumedAsync();
Task TouchSessionAsync();
event EventHandler? SessionExpired;
event EventHandler<AuthenticationResponse>? TokenRefreshed;
event EventHandler? SessionInitialized;
}
JWT-Based Authentication
WildwoodComponents uses JWT (JSON Web Tokens) for authentication. The token flow works as follows:
- The API issues an access token (short-lived JWT) and a refresh token (long-lived) upon successful login.
- The access token is stored in local storage via
ILocalStorageServiceunder the keyaccessToken. - The refresh token is stored separately under the key
refreshToken. - The
AuthenticationServicesets the access token as theAuthorization: Bearerheader on itsHttpClientfor all subsequent API calls. - The
WildwoodSessionManagerparses the JWTexpclaim and schedules a proactive refresh at 80% of the token's remaining lifetime.
AuthenticationService uses the keys accessToken, refreshToken, and user in local storage. The WildwoodSessionManager uses ww_auth_data and ww_session_expiry. Both layers must remain in sync.
Multi-Tenant Scoping
Every authentication operation is scoped by AppId. This ID determines:
- Which auth providers are available (Google, Facebook, Microsoft, Apple, GitHub, passkeys)
- Which password policy applies (minimum length, uppercase, digit, special character requirements)
- Whether captcha is required (Google reCAPTCHA configuration per app)
- Whether registration is allowed (open registration, token-based registration, or disabled)
- Whether 2FA is enforced and which methods are available
- The JWT claims issued by the API (including
app_id,company_id, roles, and permissions)
// The AppId scopes all configuration loading
<AuthenticationComponent AppId="d6e61c7a-eec5-4164-a004-9b99eb5eb6de" />
// The component automatically loads app-specific configuration:
// GET /api/AppComponentConfigurations/{appId}/auth-configuration
// GET /api/AppComponentConfigurations/{appId}/auth-providers
// GET /api/AppComponentConfigurations/{appId}/captcha
Supported Authentication Methods
| Method | Description | API Endpoint |
|---|---|---|
| Local (Email/Password) | Username + password authentication with configurable password policy | POST /api/auth/login |
| OAuth (Google, Facebook, Microsoft, Apple, GitHub) | Social login via configured OAuth providers. Providers are per-app configurable. | Provider-specific redirect flow |
| Passkeys / WebAuthn | Biometric/hardware key authentication using the Web Authentication API | POST /api/webauthn/authenticate/options, POST /api/webauthn/authenticate |
| Two-Factor Authentication | TOTP authenticator apps, email codes, SMS codes, and recovery codes | POST /api/twofactor/verify, POST /api/twofactor/send-code |
| Registration Tokens | Invite-based registration using pre-generated tokens with associated pricing models | POST /api/userregistration/register-with-token |
Service Registration
All authentication services are registered via the AddWildwoodComponents extension method:
// Program.cs
builder.Services.AddWildwoodComponents(options =>
{
options.BaseUrl = "https://your-api.example.com";
options.SessionExpirationMinutes = 60; // Session duration (default: 60)
options.EnableAutoTokenRefresh = true; // Enable proactive + reactive refresh
options.SlidingExpiration = true; // Extend session on activity
options.PersistentSession = false; // Survive browser close?
options.EnableAntiforgeryValidation = true; // CSRF protection
});
This registers IAuthenticationService, IWildwoodSessionManager, ILocalStorageService, ICaptchaService, and all required dependencies as scoped services.
IConfiguration overload:
builder.Services.AddWildwoodComponents(builder.Configuration, "WildwoodAPI");
This reads from the WildwoodAPI section in appsettings.json, including BaseUrl, SessionExpirationMinutes, EnableAutoTokenRefresh, SlidingExpiration, and PersistentSession.
Key Models
AuthenticationResponse
Returned by all successful authentication operations. Contains the JWT token pair and user identity.
public class AuthenticationResponse
{
public string UserId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public string JwtToken { get; set; } // Short-lived access token
public string RefreshToken { get; set; } // Long-lived refresh token
public bool RequiresTwoFactor { get; set; } // True if 2FA challenge needed
public bool RequiresPasswordReset { get; set; } // True if temp password used
public List<string> Roles { get; set; }
public string? CompanyId { get; set; }
public List<string> Permissions { get; set; }
// 2FA fields (only when RequiresTwoFactor == true)
public string? TwoFactorSessionId { get; set; }
public List<TwoFactorMethodInfo>? AvailableTwoFactorMethods { get; set; }
public string? DefaultTwoFactorMethod { get; set; }
public int? TwoFactorSessionExpiresIn { get; set; }
}
LoginRequest
public class LoginRequest
{
public string Username { get; set; } // Primary login identifier
public string Email { get; set; } // Optional, backward compat
public string? Password { get; set; }
public string? AppId { get; set; } // Multi-tenant scoping
public bool RememberMe { get; set; }
public string? CaptchaResponse { get; set; }
public string? Platform { get; set; } // Auto-detected: Web, iOS, Windows, etc.
public string? DeviceInfo { get; set; } // User agent + platform info
public string? TrustedDeviceToken { get; set; } // For 2FA bypass on remembered devices
public string? ProviderName { get; set; } // For OAuth flows
public string? ProviderToken { get; set; } // OAuth provider token
}
Next Steps
- Session Management — Deep dive into
WildwoodSessionManagerconfiguration and lifecycle - Token Refresh — How proactive and reactive token refresh works
- Two-Factor Authentication — 2FA methods, trusted devices, and recovery codes
- Login Flow — Step-by-step walkthrough of the complete login process