Esc

Type to search across all documentation pages...

/ Developer Docs
Feedback Docs Home Landing Page Log in

Authentication & Session Overview

How WildwoodComponents handles authentication, JWT token lifecycle, session management, and multi-tenant identity across Blazor Server, WebAssembly, and MAUI applications.

Key Concept WildwoodComponents provides a complete authentication pipeline: a Blazor UI component handles user interaction, a service layer communicates with the WildwoodAPI, and a session manager maintains JWT lifecycle with automatic refresh. All operations are scoped by 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:

  1. The API issues an access token (short-lived JWT) and a refresh token (long-lived) upon successful login.
  2. The access token is stored in local storage via ILocalStorageService under the key accessToken.
  3. The refresh token is stored separately under the key refreshToken.
  4. The AuthenticationService sets the access token as the Authorization: Bearer header on its HttpClient for all subsequent API calls.
  5. The WildwoodSessionManager parses the JWT exp claim and schedules a proactive refresh at 80% of the token's remaining lifetime.
Storage Keys The 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.

Configuration from appsettings.json You can also read options from configuration using the 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

Last updated: February 2026