diff --git a/docs/auth.md b/docs/auth.md
index 2269130..821fc1d 100644
--- a/docs/auth.md
+++ b/docs/auth.md
@@ -70,6 +70,11 @@ Since code should be documenting itself you can also take a look at the followin
- [tests/.../AuthFixture.cs](https://github.com/TobiasBuchholz/Plugin.Firebase/blob/master/tests/Plugin.Firebase.IntegrationTests/Auth/AuthFixture.cs)
- [sample/.../AuthService.cs](https://github.com/TobiasBuchholz/Plugin.Firebase/blob/master/sample/Playground/Common/Services/Auth/AuthService.cs)
+## Language
+
+Use `SetLanguageCode("fr")` (or any BCP-47 code) before invoking an Auth flow that triggers user-facing content such as password-reset emails, email-verification emails, or phone-auth SMS.
+Pass `null` or whitespace to reset to the app language (`UseAppLanguage`).
+
## Error handling
Most Auth operations can throw `FirebaseAuthException`.
@@ -79,6 +84,9 @@ The exception contains:
- `Email`: populated for account-collision cases when available
## Release notes
+- Version 4.1.0
+ - Add `ReloadCurrentUserAsync()` to refresh the currently signed in user from the backend.
+ - Add `SetLanguageCode(string?)` to control the language used for Auth-generated user-facing flows (reset/verification emails, SMS).
- Version 4.0.1
- Improve `FirebaseAuthException` mapping and expose raw error details (`ErrorCode`, `Email`, and native error metadata) to support robust UI handling.
- Version 4.0.0
diff --git a/src/Analytics/Analytics.csproj b/src/Analytics/Analytics.csproj
index 1031eff..dd34ae6 100644
--- a/src/Analytics/Analytics.csproj
+++ b/src/Analytics/Analytics.csproj
@@ -22,7 +22,7 @@
Plugin.Firebase.Analytics
- 4.0.2
+ 4.1.0
MIT
https://github.com/TobiasBuchholz/Plugin.Firebase
diff --git a/src/Auth/Auth.csproj b/src/Auth/Auth.csproj
index 382fddc..d9b0b3f 100644
--- a/src/Auth/Auth.csproj
+++ b/src/Auth/Auth.csproj
@@ -23,7 +23,7 @@
Plugin.Firebase.Auth
- 4.0.2
+ 4.1.0
MIT
https://github.com/TobiasBuchholz/Plugin.Firebase
diff --git a/src/Auth/Platforms/Android/FirebaseAuthImplementation.cs b/src/Auth/Platforms/Android/FirebaseAuthImplementation.cs
index 4a5dbdd..bc6860e 100644
--- a/src/Auth/Platforms/Android/FirebaseAuthImplementation.cs
+++ b/src/Auth/Platforms/Android/FirebaseAuthImplementation.cs
@@ -170,6 +170,28 @@ public async Task SendPasswordResetEmailAsync(string email)
await WrapAsync(_firebaseAuth.SendPasswordResetEmailAsync(email));
}
+ public async Task ReloadCurrentUserAsync()
+ {
+ var currentUser = _firebaseAuth.CurrentUser;
+ if(currentUser is null) {
+ throw new FirebaseException(
+ "CurrentUser is null. You need to be logged in to use this feature."
+ );
+ }
+
+ await WrapAsync(currentUser.ReloadAsync());
+ }
+
+ public void SetLanguageCode(string? languageCode)
+ {
+ if(string.IsNullOrWhiteSpace(languageCode)) {
+ _firebaseAuth.UseAppLanguage();
+ return;
+ }
+
+ _firebaseAuth.LanguageCode = languageCode;
+ }
+
public void UseEmulator(string host, int port)
{
_firebaseAuth.UseEmulator(host, port);
diff --git a/src/Auth/Platforms/iOS/FirebaseAuthImplementation.cs b/src/Auth/Platforms/iOS/FirebaseAuthImplementation.cs
index 8e87ebc..0a3d5f5 100644
--- a/src/Auth/Platforms/iOS/FirebaseAuthImplementation.cs
+++ b/src/Auth/Platforms/iOS/FirebaseAuthImplementation.cs
@@ -141,9 +141,11 @@ public Task SignOutAsync()
{
_firebaseAuth.SignOut(out var error);
- return error is null
- ? Task.CompletedTask
- : throw GetFirebaseAuthException(new NSErrorException(error));
+ if(error is null) {
+ return Task.CompletedTask;
+ }
+
+ throw GetFirebaseAuthException(new NSErrorException(error));
}
///
@@ -180,6 +182,28 @@ public async Task SendPasswordResetEmailAsync(string email)
await WrapAsync(_firebaseAuth.SendPasswordResetAsync(email));
}
+ public async Task ReloadCurrentUserAsync()
+ {
+ var currentUser = _firebaseAuth.CurrentUser;
+ if(currentUser is null) {
+ throw new FirebaseException(
+ "CurrentUser is null. You need to be logged in to use this feature."
+ );
+ }
+
+ await WrapAsync(currentUser.ReloadAsync());
+ }
+
+ public void SetLanguageCode(string? languageCode)
+ {
+ if(string.IsNullOrWhiteSpace(languageCode)) {
+ _firebaseAuth.UseAppLanguage();
+ return;
+ }
+
+ _firebaseAuth.LanguageCode = languageCode;
+ }
+
///
public void UseEmulator(string host, int port)
{
diff --git a/src/Auth/Shared/IFirebaseAuth.cs b/src/Auth/Shared/IFirebaseAuth.cs
index 0d0286d..117974d 100644
--- a/src/Auth/Shared/IFirebaseAuth.cs
+++ b/src/Auth/Shared/IFirebaseAuth.cs
@@ -105,6 +105,19 @@ Task SignInWithEmailAndPasswordAsync(
/// The registered user email.
Task SendPasswordResetEmailAsync(string email);
+ ///
+ /// Reloads the currently signed in user from the backend.
+ ///
+ /// Thrown when no user is signed in.
+ Task ReloadCurrentUserAsync();
+
+ ///
+ /// Sets the language used by Firebase Auth for user-facing flows such as Auth-generated emails/SMS (password reset, email verification, phone auth).
+ /// Call this before invoking an API that triggers the flow, then reset by passing null/whitespace to use the app language.
+ ///
+ /// A BCP-47 language code (e.g. "fr", "en-GB"), or null to use app language.
+ void SetLanguageCode(string? languageCode);
+
///
/// Modify this FirebaseAuth instance to communicate with the Firebase Authentication emulator.
/// Note: this must be called before this instance has been used to do any operations.
diff --git a/src/Bundled/Bundled.csproj b/src/Bundled/Bundled.csproj
index 47fd8ae..948871e 100644
--- a/src/Bundled/Bundled.csproj
+++ b/src/Bundled/Bundled.csproj
@@ -22,7 +22,7 @@
Plugin.Firebase
- 4.0.2
+ 4.1.0
MIT
https://github.com/TobiasBuchholz/Plugin.Firebase
diff --git a/src/CloudMessaging/CloudMessaging.csproj b/src/CloudMessaging/CloudMessaging.csproj
index 406f89b..3aa1e9b 100644
--- a/src/CloudMessaging/CloudMessaging.csproj
+++ b/src/CloudMessaging/CloudMessaging.csproj
@@ -23,7 +23,7 @@
Plugin.Firebase.CloudMessaging
- 4.0.2
+ 4.1.0
MIT
https://github.com/TobiasBuchholz/Plugin.Firebase
diff --git a/src/Core/Core.csproj b/src/Core/Core.csproj
index 4ee186e..7dd09fe 100644
--- a/src/Core/Core.csproj
+++ b/src/Core/Core.csproj
@@ -23,7 +23,7 @@
Plugin.Firebase.Core
- 4.0.2
+ 4.1.0
MIT
https://github.com/TobiasBuchholz/Plugin.Firebase
diff --git a/src/Crashlytics/Crashlytics.csproj b/src/Crashlytics/Crashlytics.csproj
index f6de800..c1aad96 100644
--- a/src/Crashlytics/Crashlytics.csproj
+++ b/src/Crashlytics/Crashlytics.csproj
@@ -22,7 +22,7 @@
Plugin.Firebase.Crashlytics
- 4.0.2
+ 4.1.0
MIT
https://github.com/TobiasBuchholz/Plugin.Firebase
diff --git a/src/Firestore/Firestore.csproj b/src/Firestore/Firestore.csproj
index 97f9f37..035ff1e 100644
--- a/src/Firestore/Firestore.csproj
+++ b/src/Firestore/Firestore.csproj
@@ -22,7 +22,7 @@
Plugin.Firebase.Firestore
- 4.0.2
+ 4.1.0
MIT
https://github.com/TobiasBuchholz/Plugin.Firebase
diff --git a/src/Functions/Functions.csproj b/src/Functions/Functions.csproj
index d42c97f..2314a0a 100644
--- a/src/Functions/Functions.csproj
+++ b/src/Functions/Functions.csproj
@@ -22,7 +22,7 @@
Plugin.Firebase.Functions
- 4.0.2
+ 4.1.0
MIT
https://github.com/TobiasBuchholz/Plugin.Firebase
diff --git a/src/RemoteConfig/RemoteConfig.csproj b/src/RemoteConfig/RemoteConfig.csproj
index 16d8cfb..872eab7 100644
--- a/src/RemoteConfig/RemoteConfig.csproj
+++ b/src/RemoteConfig/RemoteConfig.csproj
@@ -22,7 +22,7 @@
Plugin.Firebase.RemoteConfig
- 4.0.2
+ 4.1.0
MIT
https://github.com/TobiasBuchholz/Plugin.Firebase
diff --git a/src/Storage/Storage.csproj b/src/Storage/Storage.csproj
index 320875d..8607534 100644
--- a/src/Storage/Storage.csproj
+++ b/src/Storage/Storage.csproj
@@ -22,7 +22,7 @@
Plugin.Firebase.Storage
- 4.0.2
+ 4.1.0
MIT
https://github.com/TobiasBuchholz/Plugin.Firebase
diff --git a/tests/Plugin.Firebase.IntegrationTests/Auth/AuthFixture.cs b/tests/Plugin.Firebase.IntegrationTests/Auth/AuthFixture.cs
index ef674ff..a1c64ee 100644
--- a/tests/Plugin.Firebase.IntegrationTests/Auth/AuthFixture.cs
+++ b/tests/Plugin.Firebase.IntegrationTests/Auth/AuthFixture.cs
@@ -152,6 +152,34 @@ public async Task sends_verification_email()
await sut.CurrentUser.SendEmailVerificationAsync();
}
+ [Fact]
+ public async Task reloads_current_user()
+ {
+ var sut = CrossFirebaseAuth.Current;
+ await sut.SignInWithEmailAndPasswordAsync("reload-current-user@test.com", "123456");
+ Assert.NotNull(sut.CurrentUser);
+
+ var uid = sut.CurrentUser.Uid;
+ await sut.ReloadCurrentUserAsync();
+
+ Assert.NotNull(sut.CurrentUser);
+ Assert.Equal(uid, sut.CurrentUser.Uid);
+ }
+
+ [Fact]
+ public async Task sets_language_code()
+ {
+ var sut = CrossFirebaseAuth.Current;
+ await sut.SignInWithEmailAndPasswordAsync("set-language-code@test.com", "123456");
+
+ var ex = Record.Exception(() => {
+ sut.SetLanguageCode("fr");
+ sut.SetLanguageCode(null);
+ sut.SetLanguageCode(" ");
+ });
+ Assert.Null(ex);
+ }
+
[Fact]
public async Task deletes_user()
{
diff --git a/tests/Plugin.Firebase.UnitTests/FirebaseAuthExceptionTests.cs b/tests/Plugin.Firebase.UnitTests/FirebaseAuthExceptionTests.cs
index fe47d3b..e07adbd 100644
--- a/tests/Plugin.Firebase.UnitTests/FirebaseAuthExceptionTests.cs
+++ b/tests/Plugin.Firebase.UnitTests/FirebaseAuthExceptionTests.cs
@@ -18,10 +18,15 @@ public sealed class FirebaseAuthExceptionTests
new object[] { "ERROR_ACCOUNT_EXISTS_WITH_DIFFERENT_CREDENTIAL", FIRAuthError.AccountExistsWithDifferentCredential },
new object[] { "ERROR_CREDENTIAL_ALREADY_IN_USE", FIRAuthError.CredentialAlreadyInUse },
new object[] { "ERROR_REQUIRES_RECENT_LOGIN", FIRAuthError.RequiresRecentLogin },
+ new object[] { "RequiresRecentLogin", FIRAuthError.RequiresRecentLogin },
+ new object[] { "FIRAuthErrorCodeRequiresRecentLogin", FIRAuthError.RequiresRecentLogin },
+ new object[] { "AuthErrorCodeRequiresRecentLogin", FIRAuthError.RequiresRecentLogin },
new object[] { "ERROR_OPERATION_NOT_ALLOWED", FIRAuthError.OperationNotAllowed },
new object[] { "ERROR_INVALID_CUSTOM_TOKEN", FIRAuthError.InvalidCustomToken },
new object[] { "ERROR_CUSTOM_TOKEN_MISMATCH", FIRAuthError.CustomTokenMismatch },
new object[] { "ERROR_INVALID_USER_TOKEN", FIRAuthError.InvalidUserToken },
+ new object[] { "ERROR_USER_TOKEN_EXPIRED", FIRAuthError.UserTokenExpired },
+ new object[] { "FIRAuthErrorCodeUserTokenExpired", FIRAuthError.UserTokenExpired },
new object[] { "ERROR_KEYCHAIN_ERROR", FIRAuthError.KeychainError },
new object[] { "ERROR_INTERNAL_ERROR", FIRAuthError.InternalError },
new object[] { "ERROR_TOO_MANY_REQUESTS", FIRAuthError.TooManyRequests },
@@ -60,4 +65,4 @@ public void FromErrorCode_preserves_metadata()
Assert.Equal("domain", exception.NativeErrorDomain);
Assert.Equal(123, exception.NativeErrorCode);
}
-}
+}
\ No newline at end of file