diff --git a/src/Firebase.Auth.Tests/IntegrationTests.cs b/src/Firebase.Auth.Tests/IntegrationTests.cs
index d5d4bf4..6a522df 100644
--- a/src/Firebase.Auth.Tests/IntegrationTests.cs
+++ b/src/Firebase.Auth.Tests/IntegrationTests.cs
@@ -53,6 +53,62 @@ public void EmailTest()
auth.FirebaseToken.Should().NotBeNullOrWhiteSpace();
}
+ [TestMethod]
+ public void Unknown_email_address_should_be_reflected_by_failure_reason()
+ {
+ using (var authProvider = new FirebaseAuthProvider(new FirebaseConfig(ApiKey)))
+ {
+ try
+ {
+ authProvider.SignInWithEmailAndPasswordAsync("someinvalidaddressxxx@foo.com", FirebasePassword).Wait();
+ Assert.Fail("Sign-in should fail with invalid email.");
+ }
+ catch (Exception e)
+ {
+ var exception = (FirebaseAuthException) e.InnerException;
+ exception.Reason.Should().Be(AuthErrorReason.UnknownEmailAddress);
+ }
+ }
+ }
+
+ [TestMethod]
+ public void Invalid_email_address_format_should_be_reflected_by_failure_reason()
+ {
+ using (var authProvider = new FirebaseAuthProvider(new FirebaseConfig(ApiKey)))
+ {
+ try
+ {
+ authProvider.SignInWithEmailAndPasswordAsync("notanemailaddress", FirebasePassword).Wait();
+ Assert.Fail("Sign-in should fail with invalid email.");
+ }
+ catch (Exception e)
+ {
+ var exception = (FirebaseAuthException)e.InnerException;
+ exception.Reason.Should().Be(AuthErrorReason.InvalidEmailAddress);
+ }
+ }
+ }
+
+
+
+ [TestMethod]
+ public void Invalid_password_should_be_reflected_by_failure_reason()
+ {
+ using (var authProvider = new FirebaseAuthProvider(new FirebaseConfig(ApiKey)))
+ {
+ try
+ {
+ authProvider.SignInWithEmailAndPasswordAsync(FirebaseEmail, "xx" + FirebasePassword).Wait();
+ Assert.Fail("Sign-in should fail with invalid password.");
+ }
+ catch (Exception e)
+ {
+ var exception = (FirebaseAuthException)e.InnerException;
+ exception.Reason.Should().Be(AuthErrorReason.WrongPassword);
+ }
+ }
+ }
+
[TestMethod]
public void CreateUserTest()
{
diff --git a/src/Firebase.Auth/AuthErrorReason.cs b/src/Firebase.Auth/AuthErrorReason.cs
new file mode 100644
index 0000000..f4678f4
--- /dev/null
+++ b/src/Firebase.Auth/AuthErrorReason.cs
@@ -0,0 +1,27 @@
+namespace Firebase.Auth
+{
+ public enum AuthErrorReason
+ {
+ ///
+ /// Unknown error reason.
+ ///
+ Undefined,
+ ///
+ /// No user with a matching email address is registered.
+ ///
+ UnknownEmailAddress,
+ ///
+ /// The supplied ID is not a valid email address.
+ ///
+ InvalidEmailAddress,
+ ///
+ /// Wrong password.
+ ///
+ WrongPassword,
+ ///
+ /// The user was disabled and is not granted access anymore.
+ ///
+ UserDisabled
+
+ }
+}
\ No newline at end of file
diff --git a/src/Firebase.Auth/Firebase.Auth.csproj b/src/Firebase.Auth/Firebase.Auth.csproj
index 2d3355b..c20a106 100644
--- a/src/Firebase.Auth/Firebase.Auth.csproj
+++ b/src/Firebase.Auth/Firebase.Auth.csproj
@@ -41,6 +41,7 @@
+
diff --git a/src/Firebase.Auth/FirebaseAuthException.cs b/src/Firebase.Auth/FirebaseAuthException.cs
index 250e1e5..30e0ee4 100644
--- a/src/Firebase.Auth/FirebaseAuthException.cs
+++ b/src/Firebase.Auth/FirebaseAuthException.cs
@@ -4,12 +4,13 @@
public class FirebaseAuthException : Exception
{
- public FirebaseAuthException(string requestUrl, string requestData, string responseData, Exception innerException)
- : base(GenerateExceptionMessage(requestUrl, requestData, responseData), innerException)
+ public FirebaseAuthException(string requestUrl, string requestData, string responseData, Exception innerException, AuthErrorReason reason = AuthErrorReason.Undefined)
+ : base(GenerateExceptionMessage(requestUrl, requestData, responseData, reason), innerException)
{
this.RequestUrl = requestUrl;
this.RequestData = requestData;
this.ResponseData = responseData;
+ this.Reason = reason;
}
///
@@ -33,9 +34,18 @@ public string ResponseData
get;
}
- private static string GenerateExceptionMessage(string requestUrl, string requestData, string responseData)
+ ///
+ /// indicates why a login failed. If not resolved, defaults to
+ /// .
+ ///
+ public AuthErrorReason Reason
+ {
+ get;
+ }
+
+ private static string GenerateExceptionMessage(string requestUrl, string requestData, string responseData, AuthErrorReason errorReason)
{
- return $"Exception occured while authenticating.\nUrl: {requestUrl}\nRequest Data: {requestData}\nResponse: {responseData}";
+ return $"Exception occured while authenticating.\nUrl: {requestUrl}\nRequest Data: {requestData}\nResponse: {responseData}\nReason: {errorReason}";
}
}
}
diff --git a/src/Firebase.Auth/FirebaseAuthProvider.cs b/src/Firebase.Auth/FirebaseAuthProvider.cs
index f03dc75..d9c2040 100644
--- a/src/Firebase.Auth/FirebaseAuthProvider.cs
+++ b/src/Firebase.Auth/FirebaseAuthProvider.cs
@@ -1,10 +1,11 @@
-namespace Firebase.Auth
+using System.Diagnostics;
+
+namespace Firebase.Auth
{
using System;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
-
using Newtonsoft.Json;
///
@@ -31,7 +32,7 @@ public FirebaseAuthProvider(FirebaseConfig authConfig)
this.authConfig = authConfig;
this.client = new HttpClient();
}
-
+
///
/// Using the provided access token from third party auth provider (google, facebook...), get the firebase auth with token and basic user credentials.
///
@@ -92,7 +93,7 @@ public async Task CreateUserWithEmailAndPasswordAsync(string e
signup.User.DisplayName = displayName;
}
-
+
return signup;
}
@@ -169,7 +170,7 @@ public async Task GetLinkedAccountsAsync(string email)
///
/// Disposes all allocated resources.
///
- public void Dispose()
+ public void Dispose()
{
this.client.Dispose();
}
@@ -194,10 +195,57 @@ private async Task ExecuteWithPostContentAsync(string googleUr
}
catch (Exception ex)
{
- throw new FirebaseAuthException(googleUrl, postContent, responseData, ex);
+ AuthErrorReason errorReason = GetFailureReason(responseData);
+ throw new FirebaseAuthException(googleUrl, postContent, responseData, ex, errorReason);
+ }
+ }
+
+ ///
+ /// Resolves failure reason flags based on the returned error code.
+ ///
+ /// Currently only provides support for failed email auth flags.
+ private static AuthErrorReason GetFailureReason(string responseData)
+ {
+ var failureReason = AuthErrorReason.Undefined;
+ try
+ {
+ if (!string.IsNullOrEmpty(responseData) && responseData != "N/A")
+ {
+ //create error data template and try to parse JSON
+ var errorData = new { error = new { code = 0, message = "errorid" } };
+ errorData = JsonConvert.DeserializeAnonymousType(responseData, errorData);
+
+ //errorData is just null if different JSON was received
+ switch (errorData?.error?.message)
+ {
+ case "INVALID_PASSWORD":
+ failureReason = AuthErrorReason.WrongPassword;
+ break;
+ case "EMAIL_NOT_FOUND":
+ failureReason = AuthErrorReason.UnknownEmailAddress;
+ break;
+ case "INVALID_EMAIL":
+ failureReason = AuthErrorReason.InvalidEmailAddress;
+ break;
+ case "USER_DISABLED":
+ failureReason = AuthErrorReason.UserDisabled;
+ break;
+ }
+ }
+ }
+ catch (JsonReaderException)
+ {
+ //the response wasn't JSON - no data to be parsed
}
+ catch (Exception e)
+ {
+ Debug.WriteLine($"Unexpected error trying to parse the response: {e}");
+ }
+
+ return failureReason;
}
+
private string GetProviderId(FirebaseAuthType authType)
{
switch (authType)
@@ -209,8 +257,9 @@ private string GetProviderId(FirebaseAuthType authType)
return authType.ToEnumString();
case FirebaseAuthType.EmailAndPassword:
throw new InvalidOperationException("Email auth type cannot be used like this. Use methods specific to email & password authentication.");
- default: throw new NotImplementedException("");
+ default:
+ throw new NotImplementedException("");
}
}
}
-}
+}
\ No newline at end of file