Rystem.Authentication.Social.Blazor
10.0.4
dotnet add package Rystem.Authentication.Social.Blazor --version 10.0.4
NuGet\Install-Package Rystem.Authentication.Social.Blazor -Version 10.0.4
<PackageReference Include="Rystem.Authentication.Social.Blazor" Version="10.0.4" />
<PackageVersion Include="Rystem.Authentication.Social.Blazor" Version="10.0.4" />
<PackageReference Include="Rystem.Authentication.Social.Blazor" />
paket add Rystem.Authentication.Social.Blazor --version 10.0.4
#r "nuget: Rystem.Authentication.Social.Blazor, 10.0.4"
#:package Rystem.Authentication.Social.Blazor@10.0.4
#addin nuget:?package=Rystem.Authentication.Social.Blazor&version=10.0.4
#tool nuget:?package=Rystem.Authentication.Social.Blazor&version=10.0.4
What is Rystem?
📚 Resources
- 📖 Complete Documentation: https://rystem.net
- 🤖 MCP Server for AI: https://rystem.cloud/mcp
- 💬 Discord Community: https://discord.gg/tkWvy4WPjt
- ☕ Support the Project: https://www.buymeacoffee.com/keyserdsoze
Rystem.Authentication.Social.Blazor
Blazor UI components for social authentication (Blazor Server and WebAssembly) with built-in PKCE support for secure OAuth 2.0 flows.
✨ Key Features
- 🔐 PKCE Built-in: Automatic code_verifier generation for Microsoft OAuth (RFC 7636)
- 🎨 Ready-to-Use Components: Login buttons, logout, authentication router
- ⚡ Blazor Server & WASM: Works with both hosting models
- 🔄 Automatic Token Refresh: Handles token expiration seamlessly
- 🎯 Type-Safe: Strongly-typed user models with C# generics
- 📱 MAUI Hybrid Support: Full .NET MAUI Blazor Hybrid support with deep link OAuth flows
🆕 What's New - Mobile Platform Support
All social providers now support MAUI Blazor Hybrid! Configure platform-specific OAuth redirect URIs for seamless authentication across Web (Blazor Server/WASM), iOS (MAUI), and Android (MAUI).
Supported Platforms & Providers
| Provider | Blazor Server | Blazor WASM | MAUI iOS | MAUI Android | PKCE Support |
|---|---|---|---|---|---|
| Microsoft | ✅ | ✅ | ✅ | ✅ | ✅ |
| ✅ | ✅ | ✅ | ✅ | - |
More providers coming soon for Blazor
How It Works
- Auto-Detection: Library automatically detects platform (Web/iOS/Android) via JSInterop and compile-time symbols
- Platform-Specific URIs: Configure custom redirect URIs per platform (e.g.,
msauth://for iOS,myapp://for Android) - Deep Links: All buttons support mobile deep link OAuth callbacks through MAUI's
AppActions - No Breaking Changes: Existing Blazor Server/WASM apps work without modification
Quick Example
// Program.cs or MauiProgram.cs
builder.Services.AddSocialLoginUI(x =>
{
x.ApiUrl = "https://api.yourdomain.com";
// Platform configuration (auto-detects if not specified)
x.Platform = new PlatformConfig
{
Type = PlatformType.Auto, // Auto-detect Web/iOS/Android
// Smart redirect path detection:
// - Contains "://" -> Complete URI (mobile deep links: msauth://, myapp://)
// - Starts with "/" -> Relative path (web, auto-detects domain)
// - Empty/null -> Default "/account/login"
#if IOS
RedirectPath = "msauth://com.yourapp.bundle/auth", // Complete URI for iOS
#elif ANDROID
RedirectPath = "myapp://oauth/callback", // Complete URI for Android
#else
RedirectPath = "/account/login", // Relative path for web
#endif
LoginMode = LoginMode.Redirect
};
x.Microsoft.ClientId = builder.Configuration["Microsoft:ClientId"];
x.Google.ClientId = builder.Configuration["Google:ClientId"];
});
iOS Deep Link Configuration (Platforms/iOS/Info.plist):
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array><string>msauth</string></array>
<key>CFBundleURLName</key>
<string>com.yourapp.bundle</string>
</dict>
</array>
Android Deep Link Configuration (Platforms/Android/AndroidManifest.xml):
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="myapp" android:host="oauth" />
</intent-filter>
📖 Full Migration Guide: See PLATFORM_SUPPORT.md for detailed setup instructions, OAuth provider configuration, and troubleshooting.
📦 Installation
dotnet add package Rystem.Authentication.Social.Blazor
🚀 Quick Start
1. Install JavaScript Interop
Add to your App.razor (in <head> or before </body>):
<script src="_content/Rystem.Authentication.Social.Blazor/socialauthentications.js"></script>
2. Configure Services (Program.cs)
var builder = WebApplication.CreateBuilder(args);
// Add Razor components
builder.Services.AddRazorComponents()
.AddInteractiveServerComponents(); // or .AddInteractiveWebAssemblyComponents()
// Configure social login UI
builder.Services.AddSocialLoginUI(x =>
{
x.ApiUrl = "https://localhost:7017"; // Your API server URL
// Configure OAuth providers (only ClientId needed for client-side)
x.Microsoft.ClientId = builder.Configuration["SocialLogin:Microsoft:ClientId"];
x.Google.ClientId = builder.Configuration["SocialLogin:Google:ClientId"];
x.Facebook.ClientId = builder.Configuration["SocialLogin:Facebook:ClientId"];
x.GitHub.ClientId = builder.Configuration["SocialLogin:GitHub:ClientId"];
// Add other providers as needed
});
// Optional: Configure repository with automatic authorization headers
builder.Services.AddRepository<User, Guid>(repositoryBuilder =>
{
repositoryBuilder.WithApiClient(apiBuilder =>
{
apiBuilder.WithHttpClient("https://localhost:7017")
.WithDefaultRetryPolicy();
});
});
// Add authorization interceptor to inject Bearer tokens automatically
builder.Services.AddDefaultAuthorizationInterceptorForApiHttpClient();
var app = builder.Build();
// Configure middleware
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error", createScopeForErrors: true);
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseAntiforgery();
app.MapRazorComponents<App>()
.AddInteractiveServerRenderMode(); // or .AddInteractiveWebAssemblyRenderMode()
app.Run();
3. Update Routes.razor
Replace default router with SocialAuthenticationRouter:
<SocialAuthenticationRouter
AppAssembly="typeof(Program).Assembly"
DefaultLayout="typeof(Layout.MainLayout)">
</SocialAuthenticationRouter>
This automatically:
- Handles OAuth callbacks (
/account/login?code=...) - Manages token storage in localStorage
- Provides cascading
SocialUserWrapperparameter to all pages
4. Add Login Page
@page "/login"
@using Rystem.Authentication.Social.Blazor
<h3>Login</h3>
<SocialLogin />
@code {
// Component automatically renders all configured provider buttons
}
5. Access User in Components
@page "/dashboard"
<h3>Welcome, @SocialUser?.User?.Username</h3>
@if (SocialUser?.User != null)
{
<p>You are logged in as @SocialUser.User.Username</p>
<SocialLogout />
}
else
{
<p>Please <a href="/login">login</a></p>
}
@code {
[CascadingParameter(Name = "SocialUser")]
public SocialUserWrapper? SocialUser { get; set; }
}
🔐 PKCE Support (Microsoft OAuth)
Automatic PKCE Implementation
The library automatically implements PKCE for Microsoft OAuth:
Code Verifier Generation: When user clicks Microsoft login button
var codeVerifier = PkceGenerator.GenerateCodeVerifier(); // 43-128 chars random string var codeChallenge = PkceGenerator.GenerateCodeChallenge(codeVerifier); // SHA256 hashLocal Storage: Stores
code_verifierfor callback retrievalawait LocalStorage.SetItemAsync("microsoft_code_verifier", codeVerifier);OAuth Request: Sends
code_challengewith S256 methodhttps://login.microsoftonline.com/consumers/oauth2/v2.0/authorize ?client_id={clientId} &response_type=code &redirect_uri={redirectUri} &code_challenge={codeChallenge} &code_challenge_method=S256Token Exchange: Sends
code_verifierto API serverPOST /api/Authentication/Social/Token?provider=Microsoft&code={code} Body: { "code_verifier": "original-verifier" }Cleanup: Removes verifier from localStorage after use
Manual PKCE Usage
For custom implementations:
@inject SocialLoginLocalStorageService LocalStorage
private async Task CustomLoginAsync()
{
// Generate PKCE values
var codeVerifier = PkceGenerator.GenerateCodeVerifier();
var codeChallenge = PkceGenerator.GenerateCodeChallenge(codeVerifier);
// Store for later retrieval
await LocalStorage.SetItemAsync("custom_code_verifier", codeVerifier);
// Build OAuth URL with code_challenge
var authUrl = $"https://oauth.provider.com/authorize?code_challenge={codeChallenge}&code_challenge_method=S256";
NavigationManager.NavigateTo(authUrl);
}
🎨 UI Components
SocialLogin
Renders all configured provider buttons:
<SocialLogin />
Individual Provider Buttons
<MicrosoftButton />
<GoogleButton />
<FacebookButton />
<GitHubButton />
Custom Button Order
<SocialLogin>
<MicrosoftButton />
<GoogleButton />
<GitHubButton />
</SocialLogin>
SocialLogout
<SocialLogout />
Custom Logout
@code {
[CascadingParameter(Name = "SocialUser")]
public SocialUserWrapper? SocialUser { get; set; }
private async Task LogoutAsync()
{
if (SocialUser != null)
{
await SocialUser.LogoutAsync(refreshPage: false);
NavigationManager.NavigateTo("/login");
}
}
}
🔧 Advanced Configuration
Platform Support (Web & Mobile - MAUI Hybrid)
The library now supports platform-specific configuration for Web, iOS (MAUI), and Android (MAUI):
builder.Services.AddSocialLoginUI(x =>
{
x.ApiUrl = "https://yourdomain.com";
// Platform configuration
x.Platform = new PlatformConfig
{
Type = PlatformType.Auto, // Auto-detect (Web/iOS/Android)
// Platform-specific redirect URIs
RedirectUri = null, // null = use NavigationManager.BaseUri for web
// For mobile apps (MAUI), set explicit redirect URI:
// RedirectUri = "msauth://com.yourapp.bundle/auth", // iOS
// RedirectUri = "myapp://oauth/callback", // Android
RedirectPath = "/account/login", // Path appended to RedirectUri
LoginMode = LoginMode.Redirect // Only Redirect supported currently
};
// OAuth providers
x.Microsoft.ClientId = "your-client-id";
x.Google.ClientId = "your-client-id";
});
MAUI Hybrid Example (iOS & Android)
For Blazor Hybrid in .NET MAUI, configure deep links:
// Program.cs or MauiProgram.cs
builder.Services.AddSocialLoginUI(x =>
{
x.ApiUrl = "https://api.yourdomain.com";
// Detect platform and configure accordingly
x.Platform = new PlatformConfig
{
Type = PlatformType.Auto, // Auto-detects iOS or Android
#if IOS
RedirectUri = "msauth://com.keyserdsoze.fantasoccer/auth",
#elif ANDROID
RedirectUri = "fantasoccer://oauth/callback",
#else
RedirectUri = null, // Web: use NavigationManager.BaseUri
#endif
RedirectPath = "/account/login",
LoginMode = LoginMode.Redirect
};
x.Microsoft.ClientId = builder.Configuration["Microsoft:ClientId"];
});
iOS Configuration (Platforms/iOS/Info.plist):
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>msauth</string>
</array>
<key>CFBundleURLName</key>
<string>com.keyserdsoze.fantasoccer</string>
</dict>
</array>
Android Configuration (Platforms/Android/AndroidManifest.xml):
<activity android:name="com.microsoft.identity.client.BrowserTabActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="fantasoccer"
android:host="oauth"
android:path="/callback" />
</intent-filter>
</activity>
MAUI App Deep Link Handler (MauiProgram.cs):
builder.Services.AddSingleton<IDeepLinkHandler, DeepLinkHandler>();
// DeepLinkHandler.cs
public class DeepLinkHandler : IDeepLinkHandler
{
private readonly NavigationManager _navigationManager;
public DeepLinkHandler(NavigationManager navigationManager)
{
_navigationManager = navigationManager;
}
public void HandleDeepLink(string uri)
{
// OAuth callback from mobile OAuth flow
if (uri.Contains("code=") && uri.Contains("state="))
{
// Extract query parameters and navigate to callback page
var parsedUri = new Uri(uri);
var code = HttpUtility.ParseQueryString(parsedUri.Query).Get("code");
var state = HttpUtility.ParseQueryString(parsedUri.Query).Get("state");
_navigationManager.NavigateTo($"/account/login?code={code}&state={state}");
}
}
}
Platform Detection Utilities
Use built-in utilities for platform detection:
@inject IJSRuntime JSRuntime
@code {
private PlatformType _currentPlatform;
protected override async Task OnInitializedAsync()
{
// Async platform detection
_currentPlatform = await PlatformDetector.DetectPlatformAsync(JSRuntime);
// Or synchronous (compile-time detection)
_currentPlatform = PlatformDetector.DetectPlatformSync();
// Check if mobile
if (PlatformDetector.IsMobilePlatform(_currentPlatform))
{
// Configure mobile-specific behavior
}
// Check if Blazor Hybrid (MAUI)
if (PlatformDetector.IsBlazorHybrid())
{
// MAUI-specific initialization
}
}
}
Login Mode (Redirect)
Currently, only Redirect mode is supported in Blazor:
x.LoginMode = LoginMode.Redirect; // Default
Note: Popup mode will be added in a future release. For now, all OAuth flows use redirect navigation.
Complete MAUI Setup Example
// MauiProgram.cs
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
});
// Blazor components
builder.Services.AddMauiBlazorWebView();
// Detect platform at startup
var currentPlatform = PlatformDetector.DetectPlatformSync();
// Social authentication with platform detection
builder.Services.AddSocialLoginUI(x =>
{
x.ApiUrl = "https://api.fantasoccer.com";
x.Platform = new PlatformConfig
{
Type = currentPlatform,
RedirectUri = currentPlatform switch
{
PlatformType.iOS => "msauth://com.keyserdsoze.fantasoccer/auth",
PlatformType.Android => "fantasoccer://oauth/callback",
_ => null // Web: use NavigationManager.BaseUri
},
RedirectPath = "/account/login",
LoginMode = LoginMode.Redirect
};
// Read from configuration
x.Microsoft.ClientId = builder.Configuration["Microsoft:ClientId"];
x.Google.ClientId = builder.Configuration["Google:ClientId"];
});
// Repository with automatic authorization
builder.Services.AddRepository<User, Guid>(repositoryBuilder =>
{
repositoryBuilder.WithApiClient(apiBuilder =>
{
apiBuilder.WithHttpClient("https://api.fantasoccer.com")
.WithDefaultRetryPolicy();
});
});
builder.Services.AddDefaultAuthorizationInterceptorForApiHttpClient();
return builder.Build();
}
}
📱 Mobile OAuth Configuration (MAUI)
Microsoft Entra ID (Azure AD) for MAUI
- Go to Azure Portal → App registrations → Your app
- Under Authentication, add Mobile and desktop applications platform
- Add redirect URI:
- iOS:
msauth://com.yourapp.bundle/auth - Android:
yourapp://oauth/callback
- iOS:
- Enable ID tokens and Access tokens
- Configure PKCE (library handles automatically)
Google for MAUI
- Go to Google Cloud Console → Credentials
- Create iOS OAuth client ID:
- Bundle ID:
com.yourapp.bundle - Redirect URI: Reverse client ID format
- Bundle ID:
- Create Android OAuth client ID:
- Package name:
com.yourapp - SHA-1 fingerprint: From your keystore
- Package name:
Deep Link Best Practices
iOS Bundle ID Format:
msauth://com.yourcompany.yourapp/auth
Android Package Name Format:
yourapp://oauth/callback
Important: Deep links must match exactly between:
- OAuth provider configuration
- Platform manifest files (Info.plist, AndroidManifest.xml)
PlatformConfig.RedirectUriin your code
🔍 How Platform Configuration Works
Understanding Redirect URI Resolution
When a user clicks a social login button, the library determines the OAuth redirect URI using this priority order:
// SocialLoginManager.cs - GetFullRedirectUri() method
// Priority 1: Explicit platform.RedirectUri (highest priority)
if (!string.IsNullOrEmpty(_settings.Platform?.RedirectUri))
{
redirectUri = _settings.Platform.RedirectUri;
}
// Priority 2: NavigationManager.BaseUri (Blazor default)
else
{
redirectUri = _navigationManager.BaseUri.TrimEnd('/');
}
// Append path
var path = _settings.Platform?.RedirectPath ?? "/account/login";
return $"{redirectUri}{path}";
Example Flow (Microsoft Login on MAUI iOS)
- Setup Configuration (
MauiProgram.cs):
builder.Services.AddSocialLoginUI(x =>
{
x.ApiUrl = "https://api.yourdomain.com";
x.Platform = new PlatformConfig
{
Type = PlatformType.iOS,
RedirectUri = "msauth://com.yourapp.bundle/auth", // Mobile deep link
RedirectPath = "/account/login"
};
x.Microsoft.ClientId = "your-client-id";
});
User Clicks MicrosoftButton.razor:
- Calls
Manager.GetFullRedirectUri()→ Returns:msauth://com.yourapp.bundle/auth/account/login - Generates PKCE code_verifier and code_challenge
- Constructs OAuth URL with
Uri.EscapeDataString(redirectUri) - Navigates:
NavigationManager.NavigateTo(oauthUrl)
- Calls
OAuth Provider Redirects:
- Microsoft redirects:
msauth://com.yourapp.bundle/auth?code=ABC123&state=XYZ - MAUI deep link handler catches URL
- Navigates:
/account/login?code=ABC123&state=XYZ
- Microsoft redirects:
Token Exchange:
SocialAuthenticationRouterdetects callback- Calls API:
POST /api/Authentication/Social/Token?provider=Microsoft&code=ABC123&redirectPath=/account/login - Returns JWT token
Platform Auto-Detection Logic
// Compile-time detection (recommended for MAUI)
public static PlatformType DetectPlatformSync()
{
#if IOS
return PlatformType.iOS;
#elif ANDROID
return PlatformType.Android;
#else
return PlatformType.Web;
#endif
}
Configuration Best Practices
✅ DO:
- Use
PlatformType.Autofor automatic detection - Set
Platform.RedirectUriexplicitly for MAUI - Use
#if IOS / #elif ANDROIDcompiler directives - Register redirect URIs in OAuth provider consoles
- Configure Info.plist and AndroidManifest.xml
❌ DON'T:
- Use web URIs (
https://) for mobile apps - Skip deep link manifest configuration
- Use different
RedirectPathacross platforms
🆚 Web vs Mobile Comparison
| Feature | Blazor Server/WASM | Blazor Hybrid (MAUI) |
|---|---|---|
| Platform | Web browsers | iOS + Android |
| Redirect URI | https://yourdomain.com |
Deep link (msauth://, myapp://) |
| Login Flow | OAuth redirect | OAuth with deep link callback |
| Token Storage | localStorage (JSInterop) | Secure Storage (MAUI) |
| PKCE | ✅ Required | ✅ Required |
| Popup Mode | ⏳ Coming soon | ❌ Not applicable |
Custom Social User Model
public class CustomSocialUser : DefaultSocialUser
{
public string DisplayName { get; set; }
public Guid UserId { get; set; }
public string Avatar { get; set; }
public List<string> Roles { get; set; }
}
Access in components:
@code {
[CascadingParameter(Name = "SocialUser")]
public SocialUserWrapper<CustomSocialUser>? SocialUser { get; set; }
private void ShowUserInfo()
{
var displayName = SocialUser?.User?.DisplayName;
var userId = SocialUser?.User?.UserId;
var roles = SocialUser?.User?.Roles;
}
}
Manual Token Management
@inject SocialLoginManager LoginManager
@inject SocialLoginLocalStorageService LocalStorage
private async Task<string?> GetAccessTokenAsync()
{
var token = await LocalStorage.GetTokenAsync();
return token?.AccessToken;
}
private async Task RefreshTokenAsync()
{
var token = await LoginManager.FetchTokenAsync();
// Token automatically refreshed if expired
}
Protected API Calls
With AddDefaultAuthorizationInterceptorForApiHttpClient(), all API calls automatically include Bearer token:
@inject IRepository<Order, Guid> OrderRepository
private async Task<List<Order>> GetOrdersAsync()
{
// Authorization header automatically added
return await OrderRepository.Query()
.Where(x => x.UserId == currentUserId)
.ToListAsync();
}
🌐 OAuth Provider Configuration
Microsoft Entra ID (Azure AD)
- Go to Azure Portal → Azure Active Directory → App registrations
- Create new registration
- Set Redirect URI:
https://yourdomain.com/account/login(Web platform) - Under Authentication:
- Enable "ID tokens"
- Enable "Access tokens"
- Set "Supported account types" to "Personal Microsoft accounts only"
- Copy Application (client) ID
- Important: PKCE is automatically handled by the library
- Go to Google Cloud Console
- Create OAuth 2.0 Client ID (Web application)
- Add Authorized redirect URI:
https://yourdomain.com/account/login - Copy Client ID
- Go to Facebook Developers
- Create App → Add Facebook Login
- Set Valid OAuth Redirect URI:
https://yourdomain.com/account/login - Copy App ID
📝 appsettings.json Example
{
"SocialLogin": {
"Microsoft": {
"ClientId": "0b90db07-be9f-4b29-b673-9e8ee9265927"
},
"Google": {
"ClientId": "23769141170-lfs24avv5qrj00m4cbmrm202c0fc6gcg.apps.googleusercontent.com"
},
"Facebook": {
"ClientId": "345885718092912"
}
}
}
⚠️ Note: Only ClientId is needed on client-side. ClientSecret should only be configured on the API server.
🔗 Related Packages
- API Server:
Rystem.Authentication.Social- Backend OAuth token validation with PKCE - React Client:
rystem.authentication.social.react- React components with TypeScript - Abstractions:
Rystem.Authentication.Social.Abstractions- Shared models
📚 More Information
- Complete Docs: https://rystem.net/mcp/tools/auth-social-blazor.md
- OAuth Flow Diagram: https://rystem.net/mcp/prompts/auth-flow.md
- PKCE RFC: RFC 7636
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Microsoft.Identity.Abstractions (>= 10.0.0)
- Rystem (>= 10.0.4)
- Rystem.Authentication.Social.Abstractions (>= 10.0.4)
NuGet packages (2)
Showing the top 2 NuGet packages that depend on Rystem.Authentication.Social.Blazor:
| Package | Downloads |
|---|---|
|
Rystem.Api.Client.Authentication.BlazorServer
Rystem.Api helps you to integrate Api Server and Automated Client for Aspect-Oriented programming. |
|
|
Rystem.RepositoryFramework.Api.Client.Authentication.BlazorServer
Rystem.RepositoryFramework allows you to use correctly concepts like repository pattern, CQRS and DDD. You have interfaces for your domains, auto-generated api, auto-generated HttpClient to simplify connection "api to front-end", a functionality for auto-population in memory of your models, a functionality to simulate exceptions and waiting time from external sources to improve your implementation/business test and load test. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 10.0.4 | 163 | 2/9/2026 |
| 10.0.3 | 87,942 | 1/28/2026 |
| 10.0.1 | 209,098 | 11/12/2025 |
| 9.1.3 | 318 | 9/2/2025 |
| 9.1.2 | 764,532 | 5/29/2025 |
| 9.1.1 | 97,858 | 5/2/2025 |
| 9.0.32 | 186,702 | 4/15/2025 |
| 9.0.31 | 5,850 | 4/2/2025 |
| 9.0.30 | 88,846 | 3/26/2025 |
| 9.0.29 | 9,014 | 3/18/2025 |
| 9.0.28 | 233 | 3/17/2025 |
| 9.0.27 | 231 | 3/16/2025 |
| 9.0.26 | 282 | 3/13/2025 |
| 9.0.25 | 52,123 | 3/9/2025 |
| 9.0.21 | 333 | 3/6/2025 |
| 9.0.20 | 19,611 | 3/6/2025 |
| 9.0.19 | 310 | 3/6/2025 |
| 9.0.18 | 330 | 3/4/2025 |
| 9.0.17 | 228 | 3/1/2025 |
| 9.0.16 | 171 | 3/1/2025 |