FirebaseAuth.NET
1.8.0
dotnet add package FirebaseAuth.NET --version 1.8.0
NuGet\Install-Package FirebaseAuth.NET -Version 1.8.0
<PackageReference Include="FirebaseAuth.NET" Version="1.8.0" />
<PackageVersion Include="FirebaseAuth.NET" Version="1.8.0" />
<PackageReference Include="FirebaseAuth.NET" />
paket add FirebaseAuth.NET --version 1.8.0
#r "nuget: FirebaseAuth.NET, 1.8.0"
#:package FirebaseAuth.NET@1.8.0
#addin nuget:?package=FirebaseAuth.NET&version=1.8.0
#tool nuget:?package=FirebaseAuth.NET&version=1.8.0
π FirebaseAuth.NET
A simple, cross-platform Firebase Authentication library for MAUI, Blazor, Console, etc. targeting .NET 8, .NET 9, or .NET 10. Supports Email + Password login, registration, password reset, token persistence with secure storage abstraction, account deletion (unregister), password change, email change flow, user profile refresh, and granular error mapping.
Current version: 1.8.0
π¦ Install from NuGet
dotnet add package FirebaseAuth.NET
NuGet: https://www.nuget.org/packages/FirebaseAuth.NET
π§± Features
β
Email + Password Authentication
β
Registration (optional disable, sends verification email immediately on success)
β
Password Reset
β
Change Password
β
Start Email Change Flow (verify & change)
β
Refresh User Info (accounts:lookup)
β
Auto Token Refresh
β
Reusable SecureStorage abstraction
β
Works in MAUI, Blazor, WPF, ASP.NET, or Console apps targeting .NET 8, .NET 9, or .NET 10
β
Account deletion (Unregister)
β
Typed errors via FirebaseAuthException and AuthErrorReason
β
Robust Firebase error payload parsing (nested message formats)
π Error Reasons Overview
AuthErrorReason includes (non-exhaustive):
InvalidEmailAddress,EmailExists,EmailNotFoundInvalidPassword,WeakPassword,InvalidLoginCredentialsUserDisabled,TooManyAttemptsInvalidIdToken,TokenExpiredMissingRefreshToken,InvalidRefreshTokenRequiresRecentLogin,OperationNotAllowed
TokenExpired vs InvalidIdToken vs Refresh Token Errors
TokenExpired: ID token lifetime elapsed; library attempts refresh automatically using stored refresh token. On success you transparently continue.InvalidIdToken: Provided ID token rejected (revoked / changed context, e.g. after email change). Force re-login.MissingRefreshToken: Refresh attempted without token (corrupt / cleared state). Force logout + re-login.InvalidRefreshToken: Token revoked / malformed / deleted user. Force logout + re-login.
βοΈ Setup in a MAUI App
1οΈβ£ Create a Secure Storage Adapter
Storage/MauiSecureStorage.cs
using FirebaseAuth.NET.Storage;
namespace MyApp.Storage;
public class MauiSecureStorage : ISecureStorage
{
public Task SetAsync(string key, string value) => SecureStorage.Default.SetAsync(key, value);
public Task<string?> GetAsync(string key) => SecureStorage.Default.GetAsync(key);
public void Remove(string key) => SecureStorage.Default.Remove(key);
}
2οΈβ£ Register Dependencies
MauiProgram.cs
using FirebaseAuth.NET.Services;
using FirebaseAuth.NET.Storage;
using MyApp.Storage;
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder.Services.AddSingleton<ISecureStorage, MauiSecureStorage>();
builder.Services.AddSingleton<IFirebaseAuthService>(sp =>
{
var logger = sp.GetRequiredService<ILogger<FirebaseAuthService>>();
var storage = sp.GetRequiredService<ISecureStorage>();
var http = new HttpClient();
var apiKey = "YOUR_FIREBASE_API_KEY"; // from Firebase Console
var options = new FirebaseAuthOptions
{
ThrowOnError = true,
// AllowRegistration = false // optional
};
return new FirebaseAuthService(http, logger, storage, apiKey, options);
});
return builder.Build();
}
}
3οΈβ£ Use It Anywhere (Example Page)
try
{
var user = await _auth.LoginAsync("test@example.com", "password123");
if (user != null)
await DisplayAlert("Welcome", $"Logged in as {user.Email}", "OK");
else
await DisplayAlert("Error", "Login failed.", "OK");
}
catch (FirebaseAuthException ex)
{
switch (ex.Reason)
{
case AuthErrorReason.InvalidEmailAddress:
await DisplayAlert("Error", "Invalid email address.", "OK");
break;
case AuthErrorReason.InvalidPassword:
case AuthErrorReason.InvalidLoginCredentials:
await DisplayAlert("Error", "Invalid credentials.", "OK");
break;
case AuthErrorReason.MissingRefreshToken:
case AuthErrorReason.InvalidRefreshToken:
_auth.Logout();
await DisplayAlert("Session", "Session expired. Please log in again.", "OK");
break;
default:
await DisplayAlert("Error", ex.Message, "OK");
break;
}
}
Notes
- Changing password requires signed-in user and may need recent login.
- Email change flow invalidates old tokens; re-login then call
RefreshUserInfoAsync().
Email Change Flow
- Call
StartEmailChangeAsync(newEmail)to send verification link. - User confirms link β Firebase updates email; old ID token may fail.
- Handle
InvalidIdToken,MissingRefreshToken,InvalidRefreshTokenby forcing re-login. - Call
RefreshUserInfoAsync()to obtain updated email.
Refresh Token Failure Handling
FirebaseUser? current = null;
try
{
current = await _auth.GetCurrentUserAsync();
}
catch (FirebaseAuthException ex) when (
ex.Reason == AuthErrorReason.TokenExpired ||
ex.Reason == AuthErrorReason.InvalidIdToken ||
ex.Reason == AuthErrorReason.InvalidRefreshToken ||
ex.Reason == AuthErrorReason.MissingRefreshToken)
{
_auth.Logout();
}
If refresh fails (missing/invalid) require manual login.
4οΈβ£ Logout Example
_auth.Logout();
π§ͺ Full Console App Example
using FirebaseAuth.NET.Services;
using FirebaseAuth.NET.Storage;
using Microsoft.Extensions.Logging;
// Minimal secure storage implementation (file-based) for demo
public class FileSecureStorage : ISecureStorage
{
private readonly string _dir = Path.Combine(AppContext.BaseDirectory, "authstore");
public FileSecureStorage() => Directory.CreateDirectory(_dir);
public Task SetAsync(string key, string value)
{
File.WriteAllText(Path.Combine(_dir, key), value);
return Task.CompletedTask;
}
public Task<string?> GetAsync(string key)
{
var path = Path.Combine(_dir, key);
return Task.FromResult(File.Exists(path) ? File.ReadAllText(path) : null);
}
public void Remove(string key)
{
var path = Path.Combine(_dir, key);
if (File.Exists(path)) File.Delete(path);
}
}
var loggerFactory = LoggerFactory.Create(b => b.AddConsole());
var logger = loggerFactory.CreateLogger<FirebaseAuthService>();
var http = new HttpClient();
var storage = new FileSecureStorage();
var options = new FirebaseAuthOptions { ThrowOnError = true };
var auth = new FirebaseAuthService(http, logger, storage, "YOUR_FIREBASE_API_KEY", options);
try
{
// Register (if enabled)
var registered = await auth.RegisterAsync("user@example.com", "StrongP@ssw0rd!");
Console.WriteLine($"Registered: {registered?.Email}");
}
catch (FirebaseAuthException ex)
{
Console.WriteLine($"Registration failed ({ex.Reason}): {ex.Message}");
}
// Login
FirebaseUser? user = null;
try
{
user = await auth.LoginAsync("user@example.com", "StrongP@ssw0rd!");
Console.WriteLine($"Logged in: {user?.Email}");
}
catch (FirebaseAuthException ex)
{
Console.WriteLine($"Login failed ({ex.Reason}): {ex.Message}");
}
// Start email change
var started = await auth.StartEmailChangeAsync("new.email@example.com", canHandleCodeInApp: true);
Console.WriteLine(started ? "Email change verification sent." : "Failed to send email change link.");
Console.WriteLine("(Simulate user clicking verification link in mailbox...)\n");
// Pretend some time passes & tokens may be invalid now
await Task.Delay(TimeSpan.FromSeconds(2));
try
{
var refreshed = await auth.RefreshUserInfoAsync();
Console.WriteLine(refreshed != null ? $"Refreshed email: {refreshed.Email}" : "Refresh failed");
}
catch (FirebaseAuthException ex) when (
ex.Reason == AuthErrorReason.InvalidIdToken ||
ex.Reason == AuthErrorReason.InvalidRefreshToken ||
ex.Reason == AuthErrorReason.MissingRefreshToken)
{
Console.WriteLine($"Session invalid ({ex.Reason}). Re-login required.");
auth.Logout();
user = await auth.LoginAsync("new.email@example.com", "StrongP@ssw0rd!");
Console.WriteLine($"Re-logged in: {user?.Email}");
var updated = await auth.RefreshUserInfoAsync();
Console.WriteLine(updated != null ? $"Updated email after reauth: {updated.Email}" : "Refresh user info failed");
}
// Change password
var changedPwd = await auth.ChangePasswordAsync("An0therStr0ngP@ss!");
Console.WriteLine(changedPwd ? "Password changed." : "Password change failed.");
// Unregister
var deleted = await auth.UnregisterAsync();
Console.WriteLine(deleted ? "Account deleted." : "Account deletion failed.");
π§© Advanced
- Provide custom
ISecureStorage(KeyChain/Keystore, DPAPI, file, memory for tests). - Disable registration:
new FirebaseAuthOptions { AllowRegistration = false }. - Fine-tune error strategy:
ThrowOnError = trueto receive typed exceptions instead of null/false. - Wrap service behind your own auth facade for app-specific logic.
π Cross-platform notes
- Uses
ILoggerand Polly for transient retry (timeouts, 5xx, 429). - No platform-specific code in core library (pure .NET).
- Works in Blazor WASM (Google endpoints support CORS).
π API Surface
Key methods: LoginAsync, RegisterAsync, GetCurrentUserAsync, SendPasswordResetEmailAsync, StartEmailChangeAsync, RefreshUserInfoAsync, ChangePasswordAsync, UnregisterAsync, Logout.
π§βπ» Author
Imre SzΓΌcs β MIT License
π Contribute
Issues & PRs welcome: https://github.com/szucsim/FirebaseAuth.NET/issues
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. 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.Extensions.Logging.Abstractions (>= 9.0.10)
- Polly (>= 8.6.4)
-
net8.0
- Microsoft.Extensions.Logging.Abstractions (>= 9.0.10)
- Polly (>= 8.6.4)
-
net9.0
- Microsoft.Extensions.Logging.Abstractions (>= 9.0.10)
- Polly (>= 8.6.4)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.8.0 | 104 | 5/21/2026 |
| 1.7.1 | 516 | 11/20/2025 |
| 1.7.0 | 426 | 11/18/2025 |
| 1.6.0 | 249 | 11/16/2025 |
| 1.5.0 | 170 | 11/15/2025 |
| 1.4.4 | 302 | 11/12/2025 |
| 1.4.3 | 236 | 11/10/2025 |
| 1.4.0 | 194 | 10/25/2025 |
| 1.3.2 | 133 | 10/24/2025 |
| 1.3.1 | 137 | 10/24/2025 |
| 1.3.0 | 130 | 10/24/2025 |
| 1.2.0 | 139 | 10/24/2025 |
| 1.1.0 | 200 | 10/23/2025 |
| 1.0.1 | 204 | 10/21/2025 |
| 1.0.0 | 186 | 10/21/2025 |
1.8.0: RegisterAsync now sends Firebase email verification immediately after successful registration.
1.7.1: Added mappings for MISSING_REFRESH_TOKEN and INVALID_REFRESH_TOKEN; clarified docs about token vs refresh token invalidation and email change reauthentication flow.
1.7.0: Expands framework support, the package now targets .NET 8, .NET 9, and .NET 10.
1.6.0: Added StartEmailChangeAsync (verify and change email) and RefreshUserInfoAsync.
1.5.0: Removed ChangeEmailAsync API and feature. Updated docs and tests accordingly.
1.4.4: Fix to throw correct exceptions.
1.4.3: Internal validation improvements for error mapping.
1.4.2: Improved parsing of nested Firebase error payloads (e.g. "INVALID_ARGUMENT: INVALID_LOGIN_CREDENTIALS") so LoginAsync now throws AuthErrorReason.InvalidLoginCredentials instead of Unknown.
1.4.1: Map and throw INVALID_LOGIN_CREDENTIALS during LoginAsync when ThrowOnError is enabled.
1.4.0: Added ChangeEmailAsync to allow changing the signed-in user's email; updated README; includes XML documentation.